]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22049 Align buttons components
authorstanislavh <stanislav.honcharov@sonarsource.com>
Wed, 24 Apr 2024 13:01:18 +0000 (15:01 +0200)
committerMatteo Mara <matteo.mara@sonarsource.com>
Tue, 30 Apr 2024 08:59:03 +0000 (10:59 +0200)
42 files changed:
server/sonar-web/design-system/jest.config.js
server/sonar-web/design-system/src/components/Accordion.tsx
server/sonar-web/design-system/src/components/BorderlessAccordion.tsx
server/sonar-web/design-system/src/components/BubbleChart.tsx
server/sonar-web/design-system/src/components/ExecutionFlowAccordion.tsx
server/sonar-web/design-system/src/components/FacetBox.tsx
server/sonar-web/design-system/src/components/FacetItem.tsx
server/sonar-web/design-system/src/components/FailedQGConditionLink.tsx
server/sonar-web/design-system/src/components/IlllustredSelectionCard.tsx
server/sonar-web/design-system/src/components/SpotlightTour.tsx
server/sonar-web/design-system/src/components/Tabs.tsx
server/sonar-web/design-system/src/components/TextAccordion.tsx
server/sonar-web/design-system/src/components/ToggleButton.tsx
server/sonar-web/design-system/src/components/__tests__/Dropdown-test.tsx
server/sonar-web/design-system/src/components/buttons/BareButtons.tsx
server/sonar-web/design-system/src/components/buttons/Button.tsx [deleted file]
server/sonar-web/design-system/src/components/buttons/ButtonLink.tsx
server/sonar-web/design-system/src/components/buttons/ButtonPrimary.tsx [deleted file]
server/sonar-web/design-system/src/components/buttons/ButtonSecondary.tsx [deleted file]
server/sonar-web/design-system/src/components/buttons/DangerButtonPrimary.tsx [deleted file]
server/sonar-web/design-system/src/components/buttons/DangerButtonSecondary.tsx [deleted file]
server/sonar-web/design-system/src/components/buttons/DownloadButton.tsx
server/sonar-web/design-system/src/components/buttons/ThirdPartyButton.tsx [deleted file]
server/sonar-web/design-system/src/components/buttons/WrapperButton.tsx
server/sonar-web/design-system/src/components/buttons/__tests__/ButtonPrimary-test.tsx [deleted file]
server/sonar-web/design-system/src/components/buttons/index.ts
server/sonar-web/design-system/src/components/clipboard.tsx
server/sonar-web/design-system/src/components/code-line/LineFinding.tsx
server/sonar-web/design-system/src/components/input/FileInput.tsx
server/sonar-web/design-system/src/components/input/InputMultiSelect.tsx
server/sonar-web/design-system/src/components/modal/Modal.tsx
server/sonar-web/design-system/src/components/subnavigation/SubnavigationAccordion.tsx
server/sonar-web/design-system/src/sonar-aligned/components/buttons/BareButton.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/buttons/Button.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/buttons/ButtonPrimary.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/buttons/ButtonSecondary.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/buttons/DangerButtonPrimary.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/buttons/DangerButtonSecondary.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/buttons/ThirdPartyButton.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/buttons/__tests__/ButtonPrimary-test.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/buttons/index.ts [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/index.ts

index 317814650ab16200ed5f248f457c227fbe97db3f..7201800d75ca68b97be362ddf00a9f27f42f972f 100644 (file)
@@ -30,6 +30,7 @@ module.exports = {
     'src/components/**/*.{ts,tsx,js}',
     'src/helpers/**/*.{ts,tsx,js}',
     'src/hooks/**/*.{ts,tsx,js}',
+    'src/sonar-aligned/**/*.{ts,tsx,js}',
     '!src/helpers/{keycodes,testUtils}.{ts,tsx}',
   ],
   coverageReporters: ['lcovonly', 'text'],
index 73fc773fdeaedb06554435e6c02c757d05a2fe54..f5f464b7fa1244d980c85eb4820f4ffc13c58ba9 100644 (file)
@@ -24,8 +24,8 @@ import { uniqueId } from 'lodash';
 import React from 'react';
 import tw from 'twin.macro';
 import { themeBorder, themeColor, themeContrast } from '../helpers';
+import { BareButton } from '../sonar-aligned/components/buttons';
 import { ThemedProps } from '../types';
-import { BareButton } from './buttons';
 import { OpenCloseIndicator } from './icons/OpenCloseIndicator';
 
 interface AccordionProps {
index 9242060befb6347e9bfd9298b5b5c862ae7420c2..1fae58315d66d8bcf2c11f39bc288257d1f6b7a4 100644 (file)
@@ -20,7 +20,7 @@
 import classNames from 'classnames';
 import { uniqueId } from 'lodash';
 import * as React from 'react';
-import { BareButton } from './buttons';
+import { BareButton } from '../sonar-aligned/components/buttons';
 import { OpenCloseIndicator } from './icons/OpenCloseIndicator';
 
 interface AccordionProps {
index 9f2e0dee405c8a8fc9bb47bd0fd796a522f24434..5fa8237f4c98fe9e19cfb5a03056e0ca12e78757 100644 (file)
@@ -29,10 +29,10 @@ import * as React from 'react';
 import { AutoSizer } from 'react-virtualized/dist/commonjs/AutoSizer';
 import tw from 'twin.macro';
 import { themeColor, themeContrast } from '../helpers';
+import { ButtonSecondary } from '../sonar-aligned/components/buttons';
 import { BubbleColorVal } from '../types/charts';
 import { Note } from './Text';
 import { Tooltip } from './Tooltip';
-import { ButtonSecondary } from './buttons';
 
 const TICKS_COUNT = 5;
 
index cc37544272a81d28b6ff5f6fbebe7130db54f19d..04d8c44f66881ce325327eaf96870e639cf5a43e 100644 (file)
@@ -22,7 +22,7 @@ import classNames from 'classnames';
 import { ReactNode } from 'react';
 import tw from 'twin.macro';
 import { themeBorder, themeColor, themeContrast } from '../helpers/theme';
-import { BareButton } from './buttons';
+import { BareButton } from '../sonar-aligned/components/buttons';
 import { OpenCloseIndicator } from './icons/OpenCloseIndicator';
 
 interface Props {
index beab0da8021519446a702f609bd82c5256fd48dd..8b13dc4cac89e3498ba11cdebe5b58b886f57a2d 100644 (file)
@@ -23,11 +23,11 @@ import { uniqueId } from 'lodash';
 import * as React from 'react';
 import tw from 'twin.macro';
 import { themeColor } from '../helpers';
+import { BareButton } from '../sonar-aligned/components/buttons';
 import { Badge } from './Badge';
 import { DestructiveIcon } from './InteractiveIcon';
 import { Spinner } from './Spinner';
 import { Tooltip as SCTooltip } from './Tooltip';
-import { BareButton } from './buttons';
 import { OpenCloseIndicator } from './icons';
 import { CloseIcon } from './icons/CloseIcon';
 
index 7661f355be80c4382eb5406b002e904879577f9d..91e258c9f3ea289034e5fe954d4aec94d9ba930f 100644 (file)
@@ -23,7 +23,7 @@ import * as React from 'react';
 import tw from 'twin.macro';
 import { themeBorder, themeColor, themeContrast } from '../helpers';
 import { isDefined } from '../helpers/types';
-import { ButtonProps, ButtonSecondary } from './buttons';
+import { ButtonProps, ButtonSecondary } from '../sonar-aligned/components/buttons';
 
 export type FacetItemProps = Omit<ButtonProps, 'name' | 'onClick'> & {
   active?: boolean;
index c0095d098a75879a9558343b2ac42b48a1e20d4e..bf35fcfd35d1d7504c3c33e06686be1e9d4f566f 100644 (file)
@@ -20,7 +20,7 @@
 import styled from '@emotion/styled';
 import tw from 'twin.macro';
 import { themeColor } from '../helpers/theme';
-import { ButtonProps, DangerButtonSecondary } from './buttons';
+import { ButtonProps, DangerButtonSecondary } from '../sonar-aligned/components/buttons';
 import { ChevronRightIcon } from './icons/ChevronRightIcon';
 
 const StyledFailedQGConditionLink = styled(DangerButtonSecondary)`
index c2efbfab10dbbbb81aa8073d501abc8f74a70af1..b4cb668ec0d893843093c1bf28f46f446d6e573c 100644 (file)
@@ -22,7 +22,7 @@ import classNames from 'classnames';
 import { ReactNode } from 'react';
 import tw from 'twin.macro';
 import { themeBorder, themeColor } from '../helpers/theme';
-import { BareButton } from './buttons';
+import { BareButton } from '../sonar-aligned/components/buttons';
 
 interface Props {
   className?: string;
index de47b27411b650a98321a4fd12937700866d48d6..62bc70df15bc3d8e317deeada0fdcea341481185 100644 (file)
@@ -29,7 +29,8 @@ import ReactJoyride, {
 import tw from 'twin.macro';
 import { GLOBAL_POPUP_Z_INDEX, PopupZLevel, themeColor } from '../helpers';
 import { findAnchor } from '../helpers/dom';
-import { ButtonLink, ButtonPrimary, WrapperButton } from './buttons';
+import { ButtonPrimary } from '../sonar-aligned/components/buttons';
+import { ButtonLink, WrapperButton } from './buttons';
 import { CloseIcon } from './icons';
 import { PopupWrapper } from './popups';
 
index 959691a5ab49115bf711d37c6cf0570c14e0d62c..21a7fa765c8721755d51fa50726529f243c2b23b 100644 (file)
@@ -22,8 +22,8 @@ import { PropsWithChildren } from 'react';
 import tw from 'twin.macro';
 import { OPACITY_20_PERCENT, themeBorder, themeColor } from '../helpers';
 import { getTabId, getTabPanelId } from '../helpers/tabs';
+import { BareButton } from '../sonar-aligned/components/buttons';
 import { Badge } from './Badge';
-import { BareButton } from './buttons';
 
 type TabValueType = string | number | boolean;
 
index c8580e418a73b480bdb3f2a884cd58a1256c98e4..cbb65f6d80337915aa899c0199d7e7bdb1195bdc 100644 (file)
@@ -23,8 +23,8 @@ import { uniqueId } from 'lodash';
 import React, { ReactNode } from 'react';
 import tw from 'twin.macro';
 import { themeColor } from '../helpers';
+import { BareButton } from '../sonar-aligned/components/buttons';
 import { Note } from './Text';
-import { BareButton } from './buttons';
 import { OpenCloseIndicator } from './icons';
 
 interface Props {
index abe8d4d2b30803e06d4b26c3430f2700c55fd1e6..4c6b266b91dfd84a77ab7b95c751eb04a083894f 100644 (file)
@@ -21,8 +21,8 @@ import styled from '@emotion/styled';
 import tw from 'twin.macro';
 import { getTabId, getTabPanelId } from '../helpers/tabs';
 import { themeBorder, themeColor, themeContrast } from '../helpers/theme';
+import { ButtonSecondary } from '../sonar-aligned/components/buttons';
 import { Badge } from './Badge';
-import { ButtonSecondary } from './buttons';
 
 type ToggleButtonValueType = string | number | boolean;
 
index 14447b7cb4ab1012daf57989139052225ab53e48..eb3c7cfd4d7ffc4fb8053106db593280a3bd4843 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { screen } from '@testing-library/react';
 import { renderWithRouter } from '../../helpers/testUtils';
+import { ButtonSecondary } from '../../sonar-aligned/components/buttons';
 import { ActionsDropdown, Dropdown } from '../Dropdown';
-import { ButtonSecondary } from '../buttons';
 
 describe('Dropdown', () => {
   it('renders', async () => {
index b444499a7dc47e92768daedb590af993bd965c4d..bcdf9f50b089cd465037bf9be950c11e8e6bed4e 100644 (file)
 import styled from '@emotion/styled';
 import tw from 'twin.macro';
 import { themeBorder, themeColor, themeContrast } from '../../helpers';
-
-export const BareButton = styled.button`
-  all: unset;
-  cursor: pointer;
-
-  &:focus-visible {
-    background-color: ${themeColor('dropdownMenuHover')};
-  }
-`;
+import { BareButton } from '../../sonar-aligned/components/buttons';
 
 interface CodeViewerExpanderProps {
   direction: 'UP' | 'DOWN';
diff --git a/server/sonar-web/design-system/src/components/buttons/Button.tsx b/server/sonar-web/design-system/src/components/buttons/Button.tsx
deleted file mode 100644 (file)
index 6d17cd7..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import React from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { ThemedProps } from '../../types/theme';
-import { BaseLink, LinkProps } from '../Link';
-
-type AllowedButtonAttributes = Pick<
-  React.ButtonHTMLAttributes<HTMLButtonElement>,
-  'aria-label' | 'autoFocus' | 'id' | 'name' | 'role' | 'style' | 'title' | 'type' | 'form'
->;
-
-export interface ButtonProps extends AllowedButtonAttributes {
-  children?: React.ReactNode;
-  className?: string;
-  disabled?: boolean;
-  download?: string;
-  icon?: React.ReactNode;
-  innerRef?: React.Ref<HTMLButtonElement>;
-  isExternal?: LinkProps['isExternal'];
-  onClick?: (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => unknown;
-
-  preventDefault?: boolean;
-  reloadDocument?: LinkProps['reloadDocument'];
-  stopPropagation?: boolean;
-  target?: LinkProps['target'];
-  to?: LinkProps['to'];
-}
-
-export class Button extends React.PureComponent<ButtonProps> {
-  handleClick = (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {
-    const { disabled, onClick, stopPropagation = false, type } = this.props;
-    const { preventDefault = type !== 'submit' } = this.props;
-
-    if (preventDefault || disabled) {
-      event.preventDefault();
-    }
-
-    if (stopPropagation) {
-      event.stopPropagation();
-    }
-
-    if (onClick && !disabled) {
-      onClick(event);
-    }
-  };
-
-  render() {
-    const {
-      children,
-      disabled,
-      icon,
-      innerRef,
-      onClick,
-      preventDefault,
-      stopPropagation,
-      to,
-      type = 'button',
-      ...htmlProps
-    } = this.props;
-
-    const props = {
-      ...htmlProps,
-      'aria-disabled': disabled,
-      disabled,
-      type,
-    };
-
-    if (to) {
-      return (
-        <BaseButtonLink {...props} onClick={onClick} to={to}>
-          {icon}
-          {children}
-        </BaseButtonLink>
-      );
-    }
-
-    return (
-      <BaseButton {...props} onClick={this.handleClick} ref={innerRef}>
-        {icon}
-        {children}
-      </BaseButton>
-    );
-  }
-}
-
-export const buttonStyle = (props: ThemedProps) => css`
-  box-sizing: border-box;
-  text-decoration: none;
-  outline: none;
-  border: var(--border);
-  color: var(--color);
-  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`}
-  ${tw`sw-body-sm-highlight`}
-  ${tw`sw-py-2 sw-px-4`}
-  ${tw`sw-rounded-2`}
-  ${tw`sw-cursor-pointer`}
-
-  &:hover, &:active {
-    color: var(--color);
-    background-color: var(--backgroundHover);
-  }
-
-  &:focus,
-  &:active {
-    color: var(--color);
-    outline: ${themeBorder('focus', 'var(--focus)')(props)};
-  }
-
-  &:disabled,
-  &:disabled:hover {
-    color: ${themeContrast('buttonDisabled')(props)};
-    background-color: ${themeColor('buttonDisabled')(props)};
-    border: ${themeBorder('default', 'buttonDisabledBorder')(props)};
-
-    ${tw`sw-cursor-not-allowed`}
-  }
-
-  & > svg {
-    ${tw`sw-mr-1`}
-  }
-`;
-
-const BaseButtonLink = styled(BaseLink)`
-  ${buttonStyle}
-
-  /*
-    Workaround to apply disable style to button-link
-    as link does not have disabled attribute, using props instead 
-  */
-
-  ${({ disabled, theme }) =>
-    disabled
-      ? `&, &:hover, &:focus, &:active {
-        color: ${themeContrast('buttonDisabled')({ theme })};
-        background-color: ${themeColor('buttonDisabled')({ theme })};
-        border: ${themeBorder('default', 'buttonDisabledBorder')({ theme })};
-        cursor: not-allowed;
-      }`
-      : undefined};
-`;
-
-const BaseButton = styled.button`
-  ${buttonStyle}
-
-  /*
-   Workaround for tooltips issue with onMouseLeave in disabled buttons: 
-   https://github.com/facebook/react/issues/4251 
-  */
-  & [disabled] {
-    ${tw`sw-pointer-events-none`};
-  }
-`;
index 3f55184e764a1b48d0e5aadf052867c1d39a8c30..bf52f03599ae0fa4af48966a15ada96b448aafe6 100644 (file)
@@ -20,7 +20,7 @@
 import styled from '@emotion/styled';
 import tw from 'twin.macro';
 import { themeBorder, themeColor } from '../../helpers';
-import { BareButton } from './BareButtons';
+import { BareButton } from '../../sonar-aligned/components/buttons';
 
 export const ButtonLink = styled(BareButton)`
   color: ${themeColor('linkDefault')};
diff --git a/server/sonar-web/design-system/src/components/buttons/ButtonPrimary.tsx b/server/sonar-web/design-system/src/components/buttons/ButtonPrimary.tsx
deleted file mode 100644 (file)
index 498a144..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../helpers';
-import { ThemedProps } from '../../types';
-import { Button, ButtonProps } from './Button';
-
-export const PrimaryStyle = (props: ThemedProps) => css`
-  --background: ${themeColor('button')(props)};
-  --backgroundHover: ${themeColor('buttonHover')(props)};
-  --color: ${themeContrast('primary')(props)};
-  --focus: ${themeColor('button', OPACITY_20_PERCENT)(props)};
-  --border: ${themeBorder('default', 'transparent')(props)};
-`;
-
-export const ButtonPrimary: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
-  ${PrimaryStyle}
-`;
diff --git a/server/sonar-web/design-system/src/components/buttons/ButtonSecondary.tsx b/server/sonar-web/design-system/src/components/buttons/ButtonSecondary.tsx
deleted file mode 100644 (file)
index bd898e1..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../helpers';
-import { Button, ButtonProps } from './Button';
-
-export const ButtonSecondary: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
-  --background: ${themeColor('buttonSecondary')};
-  --backgroundHover: ${themeColor('buttonSecondaryHover')};
-  --color: ${themeContrast('buttonSecondary')};
-  --focus: ${themeColor('buttonSecondaryBorder', OPACITY_20_PERCENT)};
-  --border: ${themeBorder('default', 'buttonSecondaryBorder')};
-`;
diff --git a/server/sonar-web/design-system/src/components/buttons/DangerButtonPrimary.tsx b/server/sonar-web/design-system/src/components/buttons/DangerButtonPrimary.tsx
deleted file mode 100644 (file)
index ba8e2df..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../helpers';
-import { Button, ButtonProps } from './Button';
-
-export const DangerButtonPrimary: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
-  --background: ${themeColor('dangerButton')};
-  --backgroundHover: ${themeColor('dangerButtonHover')};
-  --color: ${themeContrast('dangerButton')};
-  --focus: ${themeColor('dangerButtonFocus', OPACITY_20_PERCENT)};
-  --border: ${themeBorder('default', 'transparent')};
-`;
diff --git a/server/sonar-web/design-system/src/components/buttons/DangerButtonSecondary.tsx b/server/sonar-web/design-system/src/components/buttons/DangerButtonSecondary.tsx
deleted file mode 100644 (file)
index 94935bf..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../helpers';
-import { Button, ButtonProps } from './Button';
-
-export const DangerButtonSecondary: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
-  --background: ${themeColor('dangerButtonSecondary')};
-  --backgroundHover: ${themeColor('dangerButtonSecondaryHover')};
-  --color: ${themeContrast('dangerButtonSecondary')};
-  --focus: ${themeColor('dangerButtonSecondaryFocus', OPACITY_20_PERCENT)};
-  --border: ${themeBorder('default', 'dangerButtonSecondaryBorder')};
-`;
index 626556d1d86390bfe9b78500c4971a9629b1889d..e367df5362285b0c89591540c12b93978c1f6633 100644 (file)
@@ -18,8 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import styled from '@emotion/styled';
-import { buttonStyle } from './Button';
-import { PrimaryStyle } from './ButtonPrimary';
+import { buttonStyle, PrimaryStyle } from '../../sonar-aligned/components/buttons';
 
 export const DownloadButton = styled.a`
   ${buttonStyle}
diff --git a/server/sonar-web/design-system/src/components/buttons/ThirdPartyButton.tsx b/server/sonar-web/design-system/src/components/buttons/ThirdPartyButton.tsx
deleted file mode 100644 (file)
index 4f85fb6..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import styled from '@emotion/styled';
-import React from 'react';
-import { OPACITY_20_PERCENT } from '../../helpers/constants';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { Button, ButtonProps } from './Button';
-
-interface ThirdPartyProps extends Omit<ButtonProps, 'Icon'> {
-  iconPath: string;
-  name: string;
-}
-
-export function ThirdPartyButton({
-  children,
-  iconPath,
-  name,
-  ...buttonProps
-}: Readonly<ThirdPartyProps>) {
-  const size = 16;
-  return (
-    <ThirdPartyButtonStyled {...buttonProps}>
-      <img alt={name} className="sw-mr-2" height={size} src={iconPath} width={size} />
-      {children}
-    </ThirdPartyButtonStyled>
-  );
-}
-
-const ThirdPartyButtonStyled: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
-  --background: ${themeColor('thirdPartyButton')};
-  --backgroundHover: ${themeColor('thirdPartyButtonHover')};
-  --color: ${themeContrast('thirdPartyButton')};
-  --focus: ${themeColor('thirdPartyButtonBorder', OPACITY_20_PERCENT)};
-  --border: ${themeBorder('default', 'thirdPartyButtonBorder')};
-`;
index 26139624a3dd39eea322b0853de60cbb5f4f0e79..30e1bdd2d054512068bd4338b19026735c005372 100644 (file)
@@ -19,7 +19,7 @@
  */
 import styled from '@emotion/styled';
 import { OPACITY_20_PERCENT, themeColor } from '../../helpers';
-import { Button, ButtonProps } from './Button';
+import { Button, ButtonProps } from '../../sonar-aligned/components/buttons';
 
 export const WrapperButton: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
   --background: none;
diff --git a/server/sonar-web/design-system/src/components/buttons/__tests__/ButtonPrimary-test.tsx b/server/sonar-web/design-system/src/components/buttons/__tests__/ButtonPrimary-test.tsx
deleted file mode 100644 (file)
index af81f1d..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { render, screen } from '@testing-library/react';
-import { ButtonPrimary } from '../ButtonPrimary';
-
-it('renders ButtonPrimary correctly', () => {
-  render(<ButtonPrimary>Hello</ButtonPrimary>);
-  expect(screen.getByRole('button', { name: 'Hello' })).toBeInTheDocument();
-});
-
-it('renders ButtonPrimary correctly when to is defined', () => {
-  render(
-    <ButtonPrimary download="http://link.com" to="http://link.com">
-      Hello
-    </ButtonPrimary>,
-  );
-  expect(screen.queryByRole('button', { name: 'Hello' })).not.toBeInTheDocument();
-  expect(screen.getByRole('link', { name: 'Hello' })).toBeInTheDocument();
-});
index 59968d556b2515fd0e6241981bc2087f10db9292..723fd19cf7fff1b5586f31099ab544eeecf8e5ec 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 export * from './BareButtons';
-export * from './Button';
 export * from './ButtonLink';
-export * from './ButtonPrimary';
-export * from './ButtonSecondary';
-export * from './DangerButtonPrimary';
-export * from './DangerButtonSecondary';
 export * from './DownloadButton';
-export * from './ThirdPartyButton';
 export * from './WrapperButton';
index 1f5767d5a330415ef7595c68ee6b57e7cb1d7156..a5c30188f6bae33352165625552a3758622e5b80 100644 (file)
@@ -21,9 +21,9 @@ import classNames from 'classnames';
 import Clipboard from 'clipboard';
 import React from 'react';
 import { INTERACTIVE_TOOLTIP_DELAY } from '../helpers/constants';
+import { ButtonSecondary } from '../sonar-aligned/components/buttons';
 import { DiscreetInteractiveIcon, InteractiveIcon, InteractiveIconSize } from './InteractiveIcon';
 import { Tooltip } from './Tooltip';
-import { ButtonSecondary } from './buttons';
 import { CopyIcon } from './icons/CopyIcon';
 import { IconProps } from './icons/Icon';
 
index f2f613c382090f56718e44a061ab04fe612122e3..0d5eda10f6dfe961c660eeb626e0f9be655365c6 100644 (file)
@@ -21,7 +21,7 @@ import styled from '@emotion/styled';
 import { forwardRef, Ref } from 'react';
 import tw from 'twin.macro';
 import { themeBorder, themeColor, themeContrast, themeShadow } from '../../helpers/theme';
-import { BareButton } from '../buttons';
+import { BareButton } from '../../sonar-aligned/components/buttons';
 
 interface Props {
   className?: string;
index 17082a3f4ac95a0e670c8ecdfa95fdd30e842ca4..8ac68f29e77755220afe7ae4edc9734303f93f70 100644 (file)
@@ -19,8 +19,8 @@
  */
 import classNames from 'classnames';
 import { useCallback, useRef, useState } from 'react';
+import { ButtonSecondary } from '../../sonar-aligned/components/buttons/ButtonSecondary';
 import { Note } from '../Text';
-import { ButtonSecondary } from '../buttons/ButtonSecondary';
 
 interface Props {
   chooseLabel: string;
index 1dc57196c19b42395dc71994482c106b13529858..39fbfece0293d4cc524117c22033552f8b4d5874 100644 (file)
 import styled from '@emotion/styled';
 import classNames from 'classnames';
 import { themeBorder } from '../../helpers';
+import { ButtonProps } from '../../sonar-aligned/components/buttons';
 import { Badge } from '../Badge';
 import { LightLabel } from '../Text';
-import { ButtonProps, WrapperButton } from '../buttons';
+import { WrapperButton } from '../buttons';
 import { ChevronDownIcon } from '../icons';
 
 interface Props extends Pick<ButtonProps, 'onClick'> {
index d7654dbce0006a6f68408e864865f0e44841f324..9b1a05caa56c0d530903f6d76d3be94b03bffedf 100644 (file)
@@ -25,8 +25,8 @@ import ReactModal from 'react-modal';
 import tw from 'twin.macro';
 import { themeColor } from '../../helpers';
 import { REACT_DOM_CONTAINER } from '../../helpers/constants';
+import { ButtonSecondary } from '../../sonar-aligned/components/buttons';
 import { Theme } from '../../types/theme';
-import { ButtonSecondary } from '../buttons';
 import { ModalBody } from './ModalBody';
 import { ModalFooter } from './ModalFooter';
 import { ModalHeader } from './ModalHeader';
index 4c1d230c57a8e7fcfbfd7def73660a1eb279e94c..ded1108c55fa1bddacdf3f61c7c3e31ba8eb3f7f 100644 (file)
@@ -21,7 +21,7 @@ import styled from '@emotion/styled';
 import { ReactNode, useCallback, useState } from 'react';
 import tw from 'twin.macro';
 import { themeColor, themeContrast } from '../../helpers/theme';
-import { BareButton } from '../buttons';
+import { BareButton } from '../../sonar-aligned/components/buttons';
 import { OpenCloseIndicator } from '../icons/OpenCloseIndicator';
 import { SubnavigationGroup } from './SubnavigationGroup';
 
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/BareButton.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/BareButton.tsx
new file mode 100644 (file)
index 0000000..02b49e3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import styled from '@emotion/styled';
+import { themeColor } from '../../../helpers';
+
+export const BareButton = styled.button`
+  all: unset;
+  cursor: pointer;
+
+  &:focus-visible {
+    background-color: ${themeColor('dropdownMenuHover')};
+  }
+`;
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
new file mode 100644 (file)
index 0000000..db5693e
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { css } from '@emotion/react';
+import styled from '@emotion/styled';
+import React from 'react';
+import tw from 'twin.macro';
+import { BaseLink, LinkProps } from '../../../components/Link';
+import { themeBorder, themeColor, themeContrast } from '../../../helpers/theme';
+import { ThemedProps } from '../../../types/theme';
+
+type AllowedButtonAttributes = Pick<
+  React.ButtonHTMLAttributes<HTMLButtonElement>,
+  'aria-label' | 'autoFocus' | 'id' | 'name' | 'role' | 'style' | 'title' | 'type' | 'form'
+>;
+
+export interface ButtonProps extends AllowedButtonAttributes {
+  children?: React.ReactNode;
+  className?: string;
+  disabled?: boolean;
+  download?: string;
+  icon?: React.ReactNode;
+  innerRef?: React.Ref<HTMLButtonElement>;
+  isExternal?: LinkProps['isExternal'];
+
+  onClick?: (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => unknown;
+  preventDefault?: boolean;
+  reloadDocument?: LinkProps['reloadDocument'];
+  showExternalIcon?: boolean;
+  stopPropagation?: boolean;
+  target?: LinkProps['target'];
+  to?: LinkProps['to'];
+}
+
+export class Button extends React.PureComponent<ButtonProps> {
+  handleClick = (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {
+    const { disabled, onClick, stopPropagation = false, type } = this.props;
+    const { preventDefault = type !== 'submit' } = this.props;
+
+    if (preventDefault || disabled) {
+      event.preventDefault();
+    }
+
+    if (stopPropagation) {
+      event.stopPropagation();
+    }
+
+    if (onClick && !disabled) {
+      onClick(event);
+    }
+  };
+
+  render() {
+    const {
+      children,
+      disabled,
+      icon,
+      innerRef,
+      onClick,
+      preventDefault,
+      stopPropagation,
+      to,
+      type = 'button',
+      ...htmlProps
+    } = this.props;
+
+    const props = {
+      ...htmlProps,
+      'aria-disabled': disabled,
+      disabled,
+      type,
+    };
+
+    if (to) {
+      return (
+        <BaseButtonLink {...props} onClick={onClick} to={to}>
+          {icon}
+          {children}
+        </BaseButtonLink>
+      );
+    }
+
+    return (
+      <BaseButton {...props} onClick={this.handleClick} ref={innerRef}>
+        {icon}
+        {children}
+      </BaseButton>
+    );
+  }
+}
+
+export const buttonStyle = (props: ThemedProps) => css`
+  box-sizing: border-box;
+  text-decoration: none;
+  outline: none;
+  border: var(--border);
+  color: var(--color);
+  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`}
+  ${tw`sw-body-sm-highlight`}
+  ${tw`sw-py-2 sw-px-4`}
+  ${tw`sw-rounded-2`}
+  ${tw`sw-cursor-pointer`}
+
+  &:hover, &:active {
+    color: var(--color);
+    background-color: var(--backgroundHover);
+  }
+
+  &:focus,
+  &:active {
+    color: var(--color);
+    outline: ${themeBorder('focus', 'var(--focus)')(props)};
+  }
+
+  &:disabled,
+  &:disabled:hover {
+    color: ${themeContrast('buttonDisabled')(props)};
+    background-color: ${themeColor('buttonDisabled')(props)};
+    border: ${themeBorder('default', 'buttonDisabledBorder')(props)};
+
+    ${tw`sw-cursor-not-allowed`}
+  }
+
+  & > svg {
+    ${tw`sw-mr-1`}
+  }
+`;
+
+const BaseButtonLink = styled(BaseLink)`
+  ${buttonStyle}
+
+  /*
+    Workaround to apply disable style to button-link
+    as link does not have disabled attribute, using props instead 
+  */
+
+  ${({ disabled, theme }) =>
+    disabled
+      ? `&, &:hover, &:focus, &:active {
+        color: ${themeContrast('buttonDisabled')({ theme })};
+        background-color: ${themeColor('buttonDisabled')({ theme })};
+        border: ${themeBorder('default', 'buttonDisabledBorder')({ theme })};
+        cursor: not-allowed;
+      }`
+      : undefined};
+`;
+
+const BaseButton = styled.button`
+  ${buttonStyle}
+
+  /*
+   Workaround for tooltips issue with onMouseLeave in disabled buttons: 
+   https://github.com/facebook/react/issues/4251 
+  */
+  & [disabled] {
+    ${tw`sw-pointer-events-none`};
+  }
+`;
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/ButtonPrimary.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/ButtonPrimary.tsx
new file mode 100644 (file)
index 0000000..a335513
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { css } from '@emotion/react';
+import styled from '@emotion/styled';
+import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../../helpers';
+import { ThemedProps } from '../../../types';
+import { Button, ButtonProps } from './Button';
+
+export const PrimaryStyle = (props: ThemedProps) => css`
+  --background: ${themeColor('button')(props)};
+  --backgroundHover: ${themeColor('buttonHover')(props)};
+  --color: ${themeContrast('primary')(props)};
+  --focus: ${themeColor('button', OPACITY_20_PERCENT)(props)};
+  --border: ${themeBorder('default', 'transparent')(props)};
+`;
+
+export const ButtonPrimary: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
+  ${PrimaryStyle}
+`;
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/ButtonSecondary.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/ButtonSecondary.tsx
new file mode 100644 (file)
index 0000000..3ee6c5f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import styled from '@emotion/styled';
+import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../../helpers';
+import { Button, ButtonProps } from './Button';
+
+export const ButtonSecondary: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
+  --background: ${themeColor('buttonSecondary')};
+  --backgroundHover: ${themeColor('buttonSecondaryHover')};
+  --color: ${themeContrast('buttonSecondary')};
+  --focus: ${themeColor('buttonSecondaryBorder', OPACITY_20_PERCENT)};
+  --border: ${themeBorder('default', 'buttonSecondaryBorder')};
+`;
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/DangerButtonPrimary.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/DangerButtonPrimary.tsx
new file mode 100644 (file)
index 0000000..b0770cd
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import styled from '@emotion/styled';
+import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../../helpers';
+import { Button, ButtonProps } from './Button';
+
+export const DangerButtonPrimary: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
+  --background: ${themeColor('dangerButton')};
+  --backgroundHover: ${themeColor('dangerButtonHover')};
+  --color: ${themeContrast('dangerButton')};
+  --focus: ${themeColor('dangerButtonFocus', OPACITY_20_PERCENT)};
+  --border: ${themeBorder('default', 'transparent')};
+`;
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/DangerButtonSecondary.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/DangerButtonSecondary.tsx
new file mode 100644 (file)
index 0000000..8815ab1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import styled from '@emotion/styled';
+import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../../helpers';
+import { Button, ButtonProps } from './Button';
+
+export const DangerButtonSecondary: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
+  --background: ${themeColor('dangerButtonSecondary')};
+  --backgroundHover: ${themeColor('dangerButtonSecondaryHover')};
+  --color: ${themeContrast('dangerButtonSecondary')};
+  --focus: ${themeColor('dangerButtonSecondaryFocus', OPACITY_20_PERCENT)};
+  --border: ${themeBorder('default', 'dangerButtonSecondaryBorder')};
+`;
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/ThirdPartyButton.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/ThirdPartyButton.tsx
new file mode 100644 (file)
index 0000000..9239e4a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import styled from '@emotion/styled';
+import React from 'react';
+import { OPACITY_20_PERCENT } from '../../../helpers/constants';
+import { themeBorder, themeColor, themeContrast } from '../../../helpers/theme';
+import { Button, ButtonProps } from './Button';
+
+interface ThirdPartyProps extends Omit<ButtonProps, 'Icon'> {
+  iconPath: string;
+  name: string;
+}
+
+export function ThirdPartyButton({
+  children,
+  iconPath,
+  name,
+  ...buttonProps
+}: Readonly<ThirdPartyProps>) {
+  const size = 16;
+  return (
+    <ThirdPartyButtonStyled {...buttonProps}>
+      <img alt={name} className="sw-mr-2" height={size} src={iconPath} width={size} />
+      {children}
+    </ThirdPartyButtonStyled>
+  );
+}
+
+const ThirdPartyButtonStyled: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
+  --background: ${themeColor('thirdPartyButton')};
+  --backgroundHover: ${themeColor('thirdPartyButtonHover')};
+  --color: ${themeContrast('thirdPartyButton')};
+  --focus: ${themeColor('thirdPartyButtonBorder', OPACITY_20_PERCENT)};
+  --border: ${themeBorder('default', 'thirdPartyButtonBorder')};
+`;
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/__tests__/ButtonPrimary-test.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/__tests__/ButtonPrimary-test.tsx
new file mode 100644 (file)
index 0000000..af81f1d
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { render, screen } from '@testing-library/react';
+import { ButtonPrimary } from '../ButtonPrimary';
+
+it('renders ButtonPrimary correctly', () => {
+  render(<ButtonPrimary>Hello</ButtonPrimary>);
+  expect(screen.getByRole('button', { name: 'Hello' })).toBeInTheDocument();
+});
+
+it('renders ButtonPrimary correctly when to is defined', () => {
+  render(
+    <ButtonPrimary download="http://link.com" to="http://link.com">
+      Hello
+    </ButtonPrimary>,
+  );
+  expect(screen.queryByRole('button', { name: 'Hello' })).not.toBeInTheDocument();
+  expect(screen.getByRole('link', { name: 'Hello' })).toBeInTheDocument();
+});
diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/buttons/index.ts b/server/sonar-web/design-system/src/sonar-aligned/components/buttons/index.ts
new file mode 100644 (file)
index 0000000..6ee90cb
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+export * from './BareButton';
+export * from './Button';
+export * from './ButtonPrimary';
+export * from './ButtonSecondary';
+export * from './DangerButtonPrimary';
+export * from './DangerButtonSecondary';
+export * from './ThirdPartyButton';
index 4aff4e3e703e1f8455d1e3aba3d7b88b88c3a6ce..2dd07df0a9cfb44e7e656211e8486e531f6032ab 100644 (file)
@@ -20,3 +20,4 @@
 
 export * from './Card';
 export * from './MetricsRatingBadge';
+export * from './buttons';