aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/design-system
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2024-10-07 18:32:15 +0200
committersonartech <sonartech@sonarsource.com>2024-10-08 20:02:47 +0000
commitaef2ea10ecee8df9eadf3d3da4e63c06a9378b8b (patch)
tree840adef6a40df1e22a584f6e4a75b4cd77c1d814 /server/sonar-web/design-system
parentf49678493a80f08984b13f8003fca362fe081c9f (diff)
downloadsonarqube-aef2ea10ecee8df9eadf3d3da4e63c06a9378b8b.tar.gz
sonarqube-aef2ea10ecee8df9eadf3d3da4e63c06a9378b8b.zip
SONAR-22290 Fix focus indicator in legacy components
Diffstat (limited to 'server/sonar-web/design-system')
-rw-r--r--server/sonar-web/design-system/src/components/Dropdown.tsx31
-rw-r--r--server/sonar-web/design-system/src/components/DropdownMenu.tsx9
-rw-r--r--server/sonar-web/design-system/src/components/FacetBox.tsx7
-rw-r--r--server/sonar-web/design-system/src/components/SpotlightTour.tsx53
-rw-r--r--server/sonar-web/design-system/src/components/Switch.tsx8
-rw-r--r--server/sonar-web/design-system/src/components/Tabs.tsx4
-rw-r--r--server/sonar-web/design-system/src/components/__tests__/Dropdown-test.tsx17
-rw-r--r--server/sonar-web/design-system/src/components/__tests__/SpotlightTour-test.tsx36
-rw-r--r--server/sonar-web/design-system/src/components/__tests__/__snapshots__/CodeSnippet-test.tsx.snap48
-rw-r--r--server/sonar-web/design-system/src/components/index.ts2
-rw-r--r--server/sonar-web/design-system/src/components/input/InputField.tsx5
-rw-r--r--server/sonar-web/design-system/src/components/input/InputSearch.tsx8
-rw-r--r--server/sonar-web/design-system/src/components/input/SearchSelectDropdownControl.tsx4
-rw-r--r--server/sonar-web/design-system/src/sonar-aligned/components/ToggleButton.tsx6
-rw-r--r--server/sonar-web/design-system/src/sonar-aligned/components/buttons/Button.tsx10
-rw-r--r--server/sonar-web/design-system/src/sonar-aligned/components/input/SelectCommon.tsx8
16 files changed, 124 insertions, 132 deletions
diff --git a/server/sonar-web/design-system/src/components/Dropdown.tsx b/server/sonar-web/design-system/src/components/Dropdown.tsx
index ab273c08f0c..cf972125f20 100644
--- a/server/sonar-web/design-system/src/components/Dropdown.tsx
+++ b/server/sonar-web/design-system/src/components/Dropdown.tsx
@@ -18,13 +18,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import { useIntl } from 'react-intl';
import { PopupPlacement, PopupZLevel } from '../helpers/positioning';
import { InputSizeKeys } from '../types/theme';
import { DropdownMenu } from './DropdownMenu';
import { DropdownToggler } from './DropdownToggler';
-import { InteractiveIcon } from './InteractiveIcon';
-import { MenuIcon } from './icons/MenuIcon';
type OnClickCallback = (event?: React.MouseEvent<HTMLElement>) => void;
type A11yAttrs = Pick<React.AriaAttributes, 'aria-controls' | 'aria-expanded' | 'aria-haspopup'> & {
@@ -137,31 +134,3 @@ export class Dropdown extends React.PureComponent<Readonly<Props>, State> {
);
}
}
-
-interface ActionsDropdownProps extends Omit<Props, 'children' | 'overlay'> {
- ariaLabel?: string;
- buttonSize?: 'small' | 'medium';
- children: React.ReactNode;
- toggleClassName?: string;
-}
-
-/** @deprecated Use DropdownMenu.Root and other DropdownMenu.* elements from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3354918914/DropdownMenus | Migration Guide}
- */
-export function ActionsDropdown(props: Readonly<ActionsDropdownProps>) {
- const { children, buttonSize, ariaLabel, toggleClassName, ...dropdownProps } = props;
-
- const intl = useIntl();
-
- return (
- <Dropdown overlay={children} {...dropdownProps}>
- <InteractiveIcon
- Icon={MenuIcon}
- aria-label={ariaLabel ?? intl.formatMessage({ id: 'menu' })}
- className={toggleClassName}
- size={buttonSize}
- stopPropagation={false}
- />
- </Dropdown>
- );
-}
diff --git a/server/sonar-web/design-system/src/components/DropdownMenu.tsx b/server/sonar-web/design-system/src/components/DropdownMenu.tsx
index 82b89ee251e..dff4f3b11e6 100644
--- a/server/sonar-web/design-system/src/components/DropdownMenu.tsx
+++ b/server/sonar-web/design-system/src/components/DropdownMenu.tsx
@@ -23,7 +23,7 @@ import classNames from 'classnames';
import React, { ForwardedRef, forwardRef } from 'react';
import tw from 'twin.macro';
import { INPUT_SIZES } from '../helpers/constants';
-import { themeBorder, themeColor, themeContrast } from '../helpers/theme';
+import { themeColor, themeContrast } from '../helpers/theme';
import { InputSizeKeys, ThemedProps } from '../types/theme';
import { BaseLink, LinkProps } from './Link';
import NavLink from './NavLink';
@@ -370,12 +370,15 @@ const itemStyle = (props: ThemedProps) => css`
color: var(--color);
background-color: ${themeColor('dropdownMenuFocus')(props)};
text-decoration: none;
- outline: ${themeBorder('focus', 'dropdownMenuFocusBorder')(props)};
- outline-offset: -4px;
border: none;
border-bottom: none;
}
+ &:focus-visible {
+ borderLeft: '2px solid var(--echoes-color-focus-default)',
+ marginLeft: '-2px',
+ }
+
&:disabled,
&.disabled {
color: ${themeContrast('dropdownMenuDisabled')(props)};
diff --git a/server/sonar-web/design-system/src/components/FacetBox.tsx b/server/sonar-web/design-system/src/components/FacetBox.tsx
index 22c4e344ce1..acf9a366e1f 100644
--- a/server/sonar-web/design-system/src/components/FacetBox.tsx
+++ b/server/sonar-web/design-system/src/components/FacetBox.tsx
@@ -188,6 +188,13 @@ const ChevronAndTitle = styled(BareButton)<{
${tw`sw-items-center`};
cursor: ${({ expandable }) => (expandable ? 'pointer' : 'default')};
+
+ &:focus-visible {
+ background: transparent;
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
+ outline-offset: 4px;
+ border-radius: var(--echoes-border-radius-200);
+ }
`;
const ClearIcon = styled(DestructiveIcon)`
diff --git a/server/sonar-web/design-system/src/components/SpotlightTour.tsx b/server/sonar-web/design-system/src/components/SpotlightTour.tsx
index caa21689bb6..69131fcaec7 100644
--- a/server/sonar-web/design-system/src/components/SpotlightTour.tsx
+++ b/server/sonar-web/design-system/src/components/SpotlightTour.tsx
@@ -19,7 +19,14 @@
*/
import { keyframes } from '@emotion/react';
import styled from '@emotion/styled';
-import { LinkStandalone } from '@sonarsource/echoes-react';
+import {
+ Button,
+ ButtonIcon,
+ ButtonVariety,
+ IconX,
+ LinkStandalone,
+ TooltipProvider,
+} from '@sonarsource/echoes-react';
import React from 'react';
import { useIntl } from 'react-intl';
import ReactJoyride, {
@@ -31,9 +38,6 @@ import { LinkProps } from 'react-router-dom';
import tw from 'twin.macro';
import { GLOBAL_POPUP_Z_INDEX, PopupZLevel, themeColor } from '../helpers';
import { findAnchor } from '../helpers/dom';
-import { ButtonPrimary } from '../sonar-aligned/components/buttons';
-import { ButtonLink, WrapperButton } from './buttons';
-import { CloseIcon } from './icons';
import { PopupWrapper } from './popups';
type Placement = 'left' | 'right' | 'top' | 'bottom' | 'center';
@@ -72,7 +76,7 @@ function TooltipComponent({
size,
isLastStep,
backProps,
- skipProps,
+ skipProps: { 'aria-label': skipPropsAriaLabel, ...skipProps },
closeProps,
primaryProps,
stepXofYLabel,
@@ -162,12 +166,13 @@ function TooltipComponent({
}}
>
<strong className="sw-typo-lg-semibold sw-mb-2">{step.title}</strong>
- <WrapperButton
- className="sw-w-[30px] sw-h-[30px] sw--mt-2 sw--mr-2 sw-flex sw-justify-center"
+ <ButtonIcon
+ Icon={IconX}
+ ariaLabel={skipPropsAriaLabel}
+ className="sw--mt-2 sw--mr-2"
+ variety={ButtonVariety.DefaultGhost}
{...skipProps}
- >
- <CloseIcon className="sw-mr-0" />
- </WrapperButton>
+ />
</div>
<div>{step.content}</div>
@@ -188,15 +193,19 @@ function TooltipComponent({
<span />
<div>
{index > 0 && (
- <ButtonLink className="sw-mr-4" {...backProps}>
+ <Button className="sw-mr-4" variety={ButtonVariety.DefaultGhost} {...backProps}>
{backProps.title}
- </ButtonLink>
+ </Button>
)}
{continuous && !isLastStep && (
- <ButtonPrimary {...primaryProps}>{primaryProps.title}</ButtonPrimary>
+ <Button variety={ButtonVariety.Primary} {...primaryProps}>
+ {primaryProps.title}
+ </Button>
)}
{(!continuous || isLastStep) && (
- <ButtonPrimary {...closeProps}>{closeProps.title}</ButtonPrimary>
+ <Button variety={ButtonVariety.Primary} {...closeProps}>
+ {closeProps.title}
+ </Button>
)}
</div>
</div>
@@ -253,13 +262,15 @@ export function SpotlightTour(props: SpotlightTourProps) {
tooltipComponent={(
tooltipProps: React.PropsWithChildren<TooltipRenderProps & { step: SpotlightTourStep }>,
) => (
- <TooltipComponent
- actionLabel={actionLabel}
- actionPath={actionPath}
- stepXofYLabel={stepXofYLabel}
- width={width}
- {...tooltipProps}
- />
+ <TooltipProvider>
+ <TooltipComponent
+ actionLabel={actionLabel}
+ actionPath={actionPath}
+ stepXofYLabel={stepXofYLabel}
+ width={width}
+ {...tooltipProps}
+ />
+ </TooltipProvider>
)}
{...otherProps}
/>
diff --git a/server/sonar-web/design-system/src/components/Switch.tsx b/server/sonar-web/design-system/src/components/Switch.tsx
index b22e425e775..397338b3d04 100644
--- a/server/sonar-web/design-system/src/components/Switch.tsx
+++ b/server/sonar-web/design-system/src/components/Switch.tsx
@@ -20,7 +20,7 @@
import styled from '@emotion/styled';
import { ForwardedRef, forwardRef } from 'react';
import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast, themeShadow } from '../helpers';
+import { themeColor, themeContrast, themeShadow } from '../helpers';
import { CheckIcon } from './icons';
interface Props {
@@ -95,7 +95,7 @@ const StyledSwitch = styled.button<StyledProps>`
background: ${({ active }) => (active ? themeColor('switchActive') : themeColor('switch'))};
border: none;
transition: 0.3s ease;
- transition-property: background, outline;
+ transition-property: background;
&:hover:not(:disabled),
&:active:not(:disabled),
@@ -113,8 +113,8 @@ const StyledSwitch = styled.button<StyledProps>`
&:focus:not(:disabled),
&:active:not(:disabled) {
- outline: ${({ active }) =>
- active ? themeBorder('focus', 'switchActive') : themeBorder('focus', 'switch')};
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
+ outline-offset: var(--echoes-focus-border-offset-default);
}
`;
diff --git a/server/sonar-web/design-system/src/components/Tabs.tsx b/server/sonar-web/design-system/src/components/Tabs.tsx
index e216eb2b33b..e498755333b 100644
--- a/server/sonar-web/design-system/src/components/Tabs.tsx
+++ b/server/sonar-web/design-system/src/components/Tabs.tsx
@@ -21,7 +21,7 @@ import styled from '@emotion/styled';
import { PropsWithChildren } from 'react';
import { FormattedMessage } from 'react-intl';
import tw from 'twin.macro';
-import { OPACITY_20_PERCENT, themeBorder, themeColor } from '../helpers';
+import { themeBorder, themeColor } from '../helpers';
import { BareButton } from '../sonar-aligned/components/buttons';
import { getTabId, getTabPanelId } from '../sonar-aligned/helpers/tabs';
import { Badge } from './Badge';
@@ -131,7 +131,7 @@ const TabButton = styled(BareButton)<{
}
&:active {
- outline: ${themeBorder('xsActive', 'tabSelected', OPACITY_20_PERCENT)};
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
z-index: 1;
}
diff --git a/server/sonar-web/design-system/src/components/__tests__/Dropdown-test.tsx b/server/sonar-web/design-system/src/components/__tests__/Dropdown-test.tsx
index eb3c7cfd4d7..fce2fd2bc67 100644
--- a/server/sonar-web/design-system/src/components/__tests__/Dropdown-test.tsx
+++ b/server/sonar-web/design-system/src/components/__tests__/Dropdown-test.tsx
@@ -20,7 +20,7 @@
import { screen } from '@testing-library/react';
import { renderWithRouter } from '../../helpers/testUtils';
import { ButtonSecondary } from '../../sonar-aligned/components/buttons';
-import { ActionsDropdown, Dropdown } from '../Dropdown';
+import { Dropdown } from '../Dropdown';
describe('Dropdown', () => {
it('renders', async () => {
@@ -90,18 +90,3 @@ describe('Dropdown', () => {
);
}
});
-
-describe('ActionsDropdown', () => {
- it('renders', () => {
- setup();
- expect(screen.getByRole('button')).toHaveAccessibleName('menu');
- });
-
- function setup() {
- return renderWithRouter(
- <ActionsDropdown id="test-menu">
- <div id="overlay" />
- </ActionsDropdown>,
- );
- }
-});
diff --git a/server/sonar-web/design-system/src/components/__tests__/SpotlightTour-test.tsx b/server/sonar-web/design-system/src/components/__tests__/SpotlightTour-test.tsx
index 830e86bce97..f95b68f1a2a 100644
--- a/server/sonar-web/design-system/src/components/__tests__/SpotlightTour-test.tsx
+++ b/server/sonar-web/design-system/src/components/__tests__/SpotlightTour-test.tsx
@@ -28,42 +28,42 @@ it('should display the spotlight tour', async () => {
renderSpotlightTour({ callback });
expect(await screen.findByRole('alertdialog')).toBeInTheDocument();
- expect(screen.getByRole('alertdialog')).toHaveTextContent(
- 'Trust The FooFoo bar is bazstep 1 of 5next',
- );
+ let dialog = screen.getByRole('alertdialog');
+ expect(dialog).toHaveTextContent('Trust The Foo');
+ expect(dialog).toHaveTextContent('Foo bar is baz');
expect(screen.getByText('step 1 of 5')).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: 'next' }));
- expect(screen.getByRole('alertdialog')).toHaveTextContent(
- 'Trust The BazBaz foo is barstep 2 of 5go_backnext',
- );
+ dialog = screen.getByRole('alertdialog');
+ expect(dialog).toHaveTextContent('Trust The Baz');
+ expect(dialog).toHaveTextContent('Baz foo is bar');
expect(callback).toHaveBeenCalled();
await user.click(screen.getByRole('button', { name: 'next' }));
- expect(screen.getByRole('alertdialog')).toHaveTextContent(
- 'Trust The BarBar baz is foostep 3 of 5go_backnext',
- );
+ dialog = screen.getByRole('alertdialog');
+ expect(dialog).toHaveTextContent('Trust The Bar');
+ expect(dialog).toHaveTextContent('Bar baz is foo');
await user.click(screen.getByRole('button', { name: 'next' }));
- expect(screen.getByRole('alertdialog')).toHaveTextContent(
- 'Trust The Foo 2Foo baz is barstep 4 of 5go_backnext',
- );
+ dialog = screen.getByRole('alertdialog');
+ expect(dialog).toHaveTextContent('Trust The Foo 2');
+ expect(dialog).toHaveTextContent('Foo baz is bar');
await user.click(screen.getByRole('button', { name: 'go_back' }));
- expect(screen.getByRole('alertdialog')).toHaveTextContent(
- 'Trust The BarBar baz is foostep 3 of 5go_backnext',
- );
+ dialog = screen.getByRole('alertdialog');
+ expect(dialog).toHaveTextContent('Trust The Bar');
+ expect(dialog).toHaveTextContent('Bar baz is foo');
await user.click(screen.getByRole('button', { name: 'next' }));
await user.click(screen.getByRole('button', { name: 'next' }));
- expect(screen.getByRole('alertdialog')).toHaveTextContent(
- 'Trust The Baz 2Baz bar is foostep 5 of 5go_backclose',
- );
+ dialog = screen.getByRole('alertdialog');
+ expect(dialog).toHaveTextContent('Trust The Baz 2');
+ expect(dialog).toHaveTextContent('Baz bar is foo');
expect(screen.queryByRole('button', { name: 'next' })).not.toBeInTheDocument();
diff --git a/server/sonar-web/design-system/src/components/__tests__/__snapshots__/CodeSnippet-test.tsx.snap b/server/sonar-web/design-system/src/components/__tests__/__snapshots__/CodeSnippet-test.tsx.snap
index 6b27c088c74..1d7aad782e8 100644
--- a/server/sonar-web/design-system/src/components/__tests__/__snapshots__/CodeSnippet-test.tsx.snap
+++ b/server/sonar-web/design-system/src/components/__tests__/__snapshots__/CodeSnippet-test.tsx.snap
@@ -24,12 +24,7 @@ exports[`should highlight code content correctly 1`] = `
border: var(--border);
color: var(--color);
background-color: var(--background);
- -webkit-transition: background-color 0.2s ease,outline 0.2s ease;
- transition: background-color 0.2s ease,outline 0.2s ease;
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
+ transition:background-color 0.2s ease,display: inline-flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
@@ -64,9 +59,14 @@ exports[`should highlight code content correctly 1`] = `
}
.emotion-4:focus,
-.emotion-4:active {
+.emotion-4:active,
+.emotion-4:focus-visible {
color: var(--color);
- outline: 4px solid var(--focus);
+}
+
+.emotion-4:focus-visible {
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
+ outline-offset: var(--echoes-focus-border-offset-default);
}
.emotion-4:disabled,
@@ -226,12 +226,7 @@ exports[`should show full size when multiline with no editing 1`] = `
border: var(--border);
color: var(--color);
background-color: var(--background);
- -webkit-transition: background-color 0.2s ease,outline 0.2s ease;
- transition: background-color 0.2s ease,outline 0.2s ease;
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
+ transition:background-color 0.2s ease,display: inline-flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
@@ -266,9 +261,14 @@ exports[`should show full size when multiline with no editing 1`] = `
}
.emotion-4:focus,
-.emotion-4:active {
+.emotion-4:active,
+.emotion-4:focus-visible {
color: var(--color);
- outline: 4px solid var(--focus);
+}
+
+.emotion-4:focus-visible {
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
+ outline-offset: var(--echoes-focus-border-offset-default);
}
.emotion-4:disabled,
@@ -430,12 +430,7 @@ exports[`should show reduced size when single line with no editing 1`] = `
border: var(--border);
color: var(--color);
background-color: var(--background);
- -webkit-transition: background-color 0.2s ease,outline 0.2s ease;
- transition: background-color 0.2s ease,outline 0.2s ease;
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
+ transition:background-color 0.2s ease,display: inline-flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
@@ -472,9 +467,14 @@ exports[`should show reduced size when single line with no editing 1`] = `
}
.emotion-4:focus,
-.emotion-4:active {
+.emotion-4:active,
+.emotion-4:focus-visible {
color: var(--color);
- outline: 4px solid var(--focus);
+}
+
+.emotion-4:focus-visible {
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
+ outline-offset: var(--echoes-focus-border-offset-default);
}
.emotion-4:disabled,
diff --git a/server/sonar-web/design-system/src/components/index.ts b/server/sonar-web/design-system/src/components/index.ts
index da0bc81f8ef..8d7292db47b 100644
--- a/server/sonar-web/design-system/src/components/index.ts
+++ b/server/sonar-web/design-system/src/components/index.ts
@@ -42,7 +42,7 @@ export * from './CodeSyntaxHighlighter';
export * from './ColorsLegend';
export * from './CoverageIndicator';
export * from './DonutChart';
-export { ActionsDropdown, Dropdown } from './Dropdown';
+export { Dropdown } from './Dropdown';
export * from './DropdownMenu';
export { DropdownToggler } from './DropdownToggler';
export * from './DuplicationsIndicator';
diff --git a/server/sonar-web/design-system/src/components/input/InputField.tsx b/server/sonar-web/design-system/src/components/input/InputField.tsx
index 2b6adb2bbff..5b3c9a04e5e 100644
--- a/server/sonar-web/design-system/src/components/input/InputField.tsx
+++ b/server/sonar-web/design-system/src/components/input/InputField.tsx
@@ -59,13 +59,13 @@ InputTextArea.displayName = 'InputTextArea';
const defaultStyle = (props: ThemedProps) => css`
--border: ${themeBorder('default', 'inputBorder')(props)};
--focusBorder: ${themeBorder('default', 'inputFocus')(props)};
- --focusOutline: ${themeBorder('focus', 'inputFocus')(props)};
+ --focusOutline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
`;
const dangerStyle = (props: ThemedProps) => css`
--border: ${themeBorder('default', 'inputDanger')(props)};
--focusBorder: ${themeBorder('default', 'inputDangerFocus')(props)};
- --focusOutline: ${themeBorder('focus', 'inputDangerFocus')(props)};
+ --focusOutline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
`;
const getInputVariant = (props: ThemedProps & { isInvalid?: boolean; isValid?: boolean }) => {
@@ -102,6 +102,7 @@ const baseStyle = (props: ThemedProps) => css`
&:focus-visible {
border: var(--focusBorder);
outline: var(--focusOutline);
+ outline-offset: var(--echoes-focus-border-offset-default);
}
&:disabled,
diff --git a/server/sonar-web/design-system/src/components/input/InputSearch.tsx b/server/sonar-web/design-system/src/components/input/InputSearch.tsx
index 9e9d5d76915..fd60b082ca5 100644
--- a/server/sonar-web/design-system/src/components/input/InputSearch.tsx
+++ b/server/sonar-web/design-system/src/components/input/InputSearch.tsx
@@ -226,7 +226,8 @@ export const StyledInputWrapper = styled.div`
&:focus,
&:active {
border: ${themeBorder('default', 'inputFocus')};
- outline: ${themeBorder('focus', 'inputFocus')};
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
+ outline-offset: var(--echoes-focus-border-offset-default);
}
&::-webkit-search-decoration,
@@ -251,6 +252,11 @@ export const StyledSearchIconWrapper = styled.div`
export const StyledInteractiveIcon = styled(InteractiveIcon)`
${tw`sw-absolute`}
${tw`sw-right-2`}
+
+ &:focus,
+ &:active {
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
+ }
`;
export const StyledNote = styled.span`
diff --git a/server/sonar-web/design-system/src/components/input/SearchSelectDropdownControl.tsx b/server/sonar-web/design-system/src/components/input/SearchSelectDropdownControl.tsx
index dbfcfb1854f..d5f40048bda 100644
--- a/server/sonar-web/design-system/src/components/input/SearchSelectDropdownControl.tsx
+++ b/server/sonar-web/design-system/src/components/input/SearchSelectDropdownControl.tsx
@@ -144,11 +144,11 @@ const StyledControl = styled.div`
&:focus-visible,
&:focus-within {
border: ${themeBorder('default', 'inputFocus')};
- outline: ${themeBorder('focus', 'inputFocus')};
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
&.is-discreet {
${tw`sw-rounded-1 sw-border-none`};
- outline: ${themeBorder('focus', 'discreetFocusBorder')};
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
}
}
`;
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/ToggleButton.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/ToggleButton.tsx
index 9c882e50fbc..1c83381b8d7 100644
--- a/server/sonar-web/design-system/src/sonar-aligned/components/ToggleButton.tsx
+++ b/server/sonar-web/design-system/src/sonar-aligned/components/ToggleButton.tsx
@@ -113,9 +113,9 @@ const OptionButton = styled(ButtonSecondary)<{ selected: boolean }>`
color: ${themeContrast('toggleHover')};
}
- &:focus,
- &:active {
- outline: ${themeBorder('focus', 'toggleFocus')};
+ &:focus-visible {
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
+ outline-offset: var(--echoes-focus-border-offset-default);
z-index: 1;
}
`;
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/Button.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/Button.tsx
index 8c3a171086a..ee91b9109d5 100644
--- a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/Button.tsx
+++ b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/Button.tsx
@@ -128,7 +128,6 @@ export const buttonStyle = (props: ThemedProps) => css`
background-color: var(--background);
transition:
background-color 0.2s ease,
- outline 0.2s ease;
${tw`sw-inline-flex sw-items-center`}
${tw`sw-h-control`}
@@ -143,9 +142,14 @@ export const buttonStyle = (props: ThemedProps) => css`
}
&:focus,
- &:active {
+ &:active,
+ &:focus-visible {
color: var(--color);
- outline: ${themeBorder('focus', 'var(--focus)')(props)};
+ }
+
+ &:focus-visible {
+ outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
+ outline-offset: var(--echoes-focus-border-offset-default);
}
&:disabled,
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/input/SelectCommon.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/input/SelectCommon.tsx
index 8e89171aeb7..a5c8b75b996 100644
--- a/server/sonar-web/design-system/src/sonar-aligned/components/input/SelectCommon.tsx
+++ b/server/sonar-web/design-system/src/sonar-aligned/components/input/SelectCommon.tsx
@@ -147,7 +147,11 @@ export function selectStyle<
cursor: 'pointer',
background: themeColor('inputBackground')({ theme }),
transition: 'border 0.2s ease, outline 0.2s ease',
- outline: isFocused && !menuIsOpen ? themeBorder('focus', 'inputFocus')({ theme }) : 'none',
+ outline:
+ isFocused && !menuIsOpen
+ ? 'var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default)'
+ : 'none',
+ borderRadius: '4px',
...(isDisabled && {
color: themeContrast('inputDisabled')({ theme }),
background: themeColor('inputDisabled')({ theme }),
@@ -164,9 +168,11 @@ export function selectStyle<
}),
option: (base, { isFocused, isSelected }) => ({
...base,
+ borderLeft: '2px solid transparent',
...((isSelected || isFocused) && {
background: themeColor('selectOptionSelected')({ theme }),
color: themeContrast('primaryLight')({ theme }),
+ borderLeftColor: 'var(--echoes-color-focus-default)',
}),
}),
singleValue: (base) => ({