diff options
author | Revanshu Paliwal <revanshu.paliwal@sonarsource.com> | 2023-06-27 12:16:58 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-07-04 20:03:09 +0000 |
commit | a2124bcdd58dadee846cb87eaa77f4d9c2cd331a (patch) | |
tree | 2a433f281d7bbc7a6b16841b7a09fabd0eefb56f /server | |
parent | ebece82669c46e8657d10407ee1d5dc957af3a6c (diff) | |
download | sonarqube-a2124bcdd58dadee846cb87eaa77f4d9c2cd331a.tar.gz sonarqube-a2124bcdd58dadee846cb87eaa77f4d9c2cd331a.zip |
[NO-JIRA] Design system refactor: inputs and buttons
Diffstat (limited to 'server')
44 files changed, 664 insertions, 408 deletions
diff --git a/server/sonar-web/design-system/src/components/ColorsLegend.tsx b/server/sonar-web/design-system/src/components/ColorsLegend.tsx index c5f6e2f1082..5b5ed6d8555 100644 --- a/server/sonar-web/design-system/src/components/ColorsLegend.tsx +++ b/server/sonar-web/design-system/src/components/ColorsLegend.tsx @@ -20,11 +20,10 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import tw from 'twin.macro'; +import { themeBorder, themeColor, themeContrast } from '../helpers'; import { BubbleColorVal } from '../types/charts'; -import { Checkbox } from './Checkbox'; import Tooltip from './Tooltip'; - -import { themeBorder, themeColor, themeContrast } from '../helpers'; +import { Checkbox } from './input/Checkbox'; export interface ColorFilterOption { ariaLabel?: string; diff --git a/server/sonar-web/design-system/src/components/DropdownMenu.tsx b/server/sonar-web/design-system/src/components/DropdownMenu.tsx index 74c41581703..d6cd692bac0 100644 --- a/server/sonar-web/design-system/src/components/DropdownMenu.tsx +++ b/server/sonar-web/design-system/src/components/DropdownMenu.tsx @@ -25,12 +25,12 @@ import tw from 'twin.macro'; import { INPUT_SIZES } from '../helpers/constants'; import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; import { InputSizeKeys, ThemedProps } from '../types/theme'; -import { Checkbox } from './Checkbox'; import { BaseLink, LinkProps } from './Link'; import NavLink from './NavLink'; -import { RadioButton } from './RadioButton'; import Tooltip from './Tooltip'; import { ClipboardBase } from './clipboard'; +import { Checkbox } from './input/Checkbox'; +import { RadioButton } from './input/RadioButton'; interface Props extends React.HtmlHTMLAttributes<HTMLMenuElement> { children?: React.ReactNode; diff --git a/server/sonar-web/design-system/src/components/SelectionCard.tsx b/server/sonar-web/design-system/src/components/SelectionCard.tsx index 31df423e578..41c5541a3ea 100644 --- a/server/sonar-web/design-system/src/components/SelectionCard.tsx +++ b/server/sonar-web/design-system/src/components/SelectionCard.tsx @@ -22,9 +22,9 @@ import classNames from 'classnames'; import tw from 'twin.macro'; import { translate } from '../helpers/l10n'; import { themeBorder, themeColor, themeContrast, themeShadow } from '../helpers/theme'; -import { RadioButtonStyled } from './RadioButton'; import { LightLabel } from './Text'; import { RecommendedIcon } from './icons/RecommendedIcon'; +import { RadioButtonStyled } from './input/RadioButton'; export interface SelectionCardProps { children?: React.ReactNode; diff --git a/server/sonar-web/design-system/src/components/TagsSelector.tsx b/server/sonar-web/design-system/src/components/TagsSelector.tsx index 9a748075138..4e1f7b47f70 100644 --- a/server/sonar-web/design-system/src/components/TagsSelector.tsx +++ b/server/sonar-web/design-system/src/components/TagsSelector.tsx @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { MultiSelectMenu } from './MultiSelectMenu'; +import { MultiSelectMenu } from './input/MultiSelectMenu'; interface Props { allowNewElements?: boolean; diff --git a/server/sonar-web/design-system/src/components/buttons.tsx b/server/sonar-web/design-system/src/components/buttons.tsx deleted file mode 100644 index e71a3cee200..00000000000 --- a/server/sonar-web/design-system/src/components/buttons.tsx +++ /dev/null @@ -1,314 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { OPACITY_20_PERCENT } from '../helpers/constants'; -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']; -} - -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> - ); - } -} - -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 { - 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} -`; - -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`}; - } -`; - -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<ButtonProps> = styled(Button)` - ${PrimaryStyle} -`; - -export const DownloadButton = styled.a` - ${buttonStyle} - ${PrimaryStyle} - &:hover { - border-bottom-color: transparent; - } -`; - -export const ButtonSecondary: React.FC<ButtonProps> = styled(Button)` - --background: ${themeColor('buttonSecondary')}; - --backgroundHover: ${themeColor('buttonSecondaryHover')}; - --color: ${themeContrast('buttonSecondary')}; - --focus: ${themeColor('buttonSecondaryBorder', OPACITY_20_PERCENT)}; - --border: ${themeBorder('default', 'buttonSecondaryBorder')}; - - &:hover, - &:active, - &:focus { - border-color: ${themeColor('buttonSecondaryBorder')}; - } -`; - -export const DangerButtonPrimary: React.FC<ButtonProps> = styled(Button)` - --background: ${themeColor('dangerButton')}; - --backgroundHover: ${themeColor('dangerButtonHover')}; - --color: ${themeContrast('dangerButton')}; - --focus: ${themeColor('dangerButtonFocus', OPACITY_20_PERCENT)}; - --border: ${themeBorder('default', 'transparent')}; -`; - -export const DangerButtonSecondary: React.FC<ButtonProps> = styled(Button)` - --background: ${themeColor('dangerButtonSecondary')}; - --backgroundHover: ${themeColor('dangerButtonSecondaryHover')}; - --color: ${themeContrast('dangerButtonSecondary')}; - --focus: ${themeColor('dangerButtonSecondaryFocus', OPACITY_20_PERCENT)}; - --border: ${themeBorder('default', 'dangerButtonSecondaryBorder')}; - - &:hover, - &:active, - &:focus { - border-color: ${themeColor('dangerButtonSecondaryBorder')}; - } -`; - -export const WrapperButton: React.FC<ButtonProps> = styled(Button)` - --background: none; - --backgroundHover: none; - --color: none; - --focus: ${themeColor('button', OPACITY_20_PERCENT)}; - --border: none; -`; - -interface ThirdPartyProps extends Omit<ButtonProps, 'Icon'> { - iconPath: string; - name: string; -} - -export function ThirdPartyButton({ children, iconPath, name, ...buttonProps }: ThirdPartyProps) { - const size = 16; - return ( - <ThirdPartyButtonStyled {...buttonProps}> - <img alt={name} className="sw-mr-1" height={size} src={iconPath} width={size} /> - {children} - </ThirdPartyButtonStyled> - ); -} - -const ThirdPartyButtonStyled: React.FC<ButtonProps> = styled(Button)` - --background: ${themeColor('thirdPartyButton')}; - --backgroundHover: ${themeColor('thirdPartyButtonHover')}; - --color: ${themeContrast('thirdPartyButton')}; - --focus: ${themeColor('thirdPartyButtonBorder', OPACITY_20_PERCENT)}; - --border: ${themeBorder('default', 'thirdPartyButtonBorder')}; -`; - -export const BareButton = styled.button` - all: unset; - cursor: pointer; - - &:focus-visible { - background-color: ${themeColor('dropdownMenuHover')}; - } -`; - -interface CodeViewerExpanderProps { - direction: 'UP' | 'DOWN'; -} - -export const CodeViewerExpander = styled(BareButton)<CodeViewerExpanderProps>` - ${tw`sw-flex sw-items-center sw-gap-2`} - ${tw`sw-px-2 sw-py-1`} - ${tw`sw-code`} - ${tw`sw-w-full`} - ${tw`sw-box-border`} - - color: ${themeContrast('codeLineEllipsis')}; - background-color: ${themeColor('codeLineEllipsis')}; - - &:hover { - color: ${themeContrast('codeLineEllipsisHover')}; - background-color: ${themeColor('codeLineEllipsisHover')}; - } - - border-top: ${(props) => - props.direction === 'DOWN' ? themeBorder('default', 'codeLineBorder') : 'none'}; - - border-bottom: ${(props) => - props.direction === 'UP' ? themeBorder('default', 'codeLineBorder') : 'none'}; -`; - -export const IssueIndicatorButton = styled(BareButton)` - color: ${themeColor('codeLineMeta')}; - text-decoration: none; - - ${tw`sw-whitespace-nowrap`} -`; - -export const DuplicationBlock = styled(BareButton)` - background-color: ${themeColor('codeLineDuplication')}; - outline: none; - - ${tw`sw-block`} - ${tw`sw-w-1 sw-h-full`} - ${tw`sw-ml-1/2`} - ${tw`sw-cursor-pointer`} -`; - -export const LineSCMStyled = styled(BareButton)` - outline: none; - - ${tw`sw-pr-2`} - ${tw`sw-truncate`} - ${tw`sw-whitespace-nowrap`} - ${tw`sw-cursor-pointer`} - ${tw`sw-w-full sw-h-full`} - -&:hover { - color: ${themeColor('codeLineMetaHover')}; - } -`; diff --git a/server/sonar-web/design-system/src/components/buttons/BareButtons.tsx b/server/sonar-web/design-system/src/components/buttons/BareButtons.tsx new file mode 100644 index 00000000000..2d3842daa3b --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/BareButtons.tsx @@ -0,0 +1,89 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 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')}; + } +`; + +interface CodeViewerExpanderProps { + direction: 'UP' | 'DOWN'; +} + +export const CodeViewerExpander = styled(BareButton)<CodeViewerExpanderProps>` + ${tw`sw-flex sw-items-center sw-gap-2`} + ${tw`sw-px-2 sw-py-1`} + ${tw`sw-code`} + ${tw`sw-w-full`} + ${tw`sw-box-border`} + + color: ${themeContrast('codeLineEllipsis')}; + background-color: ${themeColor('codeLineEllipsis')}; + + &:hover { + color: ${themeContrast('codeLineEllipsisHover')}; + background-color: ${themeColor('codeLineEllipsisHover')}; + } + + border-top: ${(props) => + props.direction === 'DOWN' ? themeBorder('default', 'codeLineBorder') : 'none'}; + + border-bottom: ${(props) => + props.direction === 'UP' ? themeBorder('default', 'codeLineBorder') : 'none'}; +`; + +export const IssueIndicatorButton = styled(BareButton)` + color: ${themeColor('codeLineMeta')}; + text-decoration: none; + + ${tw`sw-whitespace-nowrap`} +`; + +export const DuplicationBlock = styled(BareButton)` + background-color: ${themeColor('codeLineDuplication')}; + outline: none; + + ${tw`sw-block`} + ${tw`sw-w-1 sw-h-full`} + ${tw`sw-ml-1/2`} + ${tw`sw-cursor-pointer`} +`; + +export const LineSCMStyled = styled(BareButton)` + outline: none; + + ${tw`sw-pr-2`} + ${tw`sw-truncate`} + ${tw`sw-whitespace-nowrap`} + ${tw`sw-cursor-pointer`} + ${tw`sw-w-full sw-h-full`} + +&:hover { + color: ${themeColor('codeLineMetaHover')}; + } +`; diff --git a/server/sonar-web/design-system/src/components/buttons/Button.tsx b/server/sonar-web/design-system/src/components/buttons/Button.tsx new file mode 100644 index 00000000000..3a969b0a1ff --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/Button.tsx @@ -0,0 +1,163 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 { + 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} +`; + +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/components/buttons/ButtonPrimary.tsx b/server/sonar-web/design-system/src/components/buttons/ButtonPrimary.tsx new file mode 100644 index 00000000000..117456532b6 --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/ButtonPrimary.tsx @@ -0,0 +1,37 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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<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 new file mode 100644 index 00000000000..8769d3f4052 --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/ButtonSecondary.tsx @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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<ButtonProps> = styled(Button)` + --background: ${themeColor('buttonSecondary')}; + --backgroundHover: ${themeColor('buttonSecondaryHover')}; + --color: ${themeContrast('buttonSecondary')}; + --focus: ${themeColor('buttonSecondaryBorder', OPACITY_20_PERCENT)}; + --border: ${themeBorder('default', 'buttonSecondaryBorder')}; + + &:hover, + &:active, + &:focus { + border-color: ${themeColor('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 new file mode 100644 index 00000000000..d954a539dfa --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/DangerButtonPrimary.tsx @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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<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 new file mode 100644 index 00000000000..0decc1751b3 --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/DangerButtonSecondary.tsx @@ -0,0 +1,37 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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<ButtonProps> = styled(Button)` + --background: ${themeColor('dangerButtonSecondary')}; + --backgroundHover: ${themeColor('dangerButtonSecondaryHover')}; + --color: ${themeContrast('dangerButtonSecondary')}; + --focus: ${themeColor('dangerButtonSecondaryFocus', OPACITY_20_PERCENT)}; + --border: ${themeBorder('default', 'dangerButtonSecondaryBorder')}; + + &:hover, + &:active, + &:focus { + border-color: ${themeColor('dangerButtonSecondaryBorder')}; + } +`; diff --git a/server/sonar-web/design-system/src/components/buttons/DownloadButton.tsx b/server/sonar-web/design-system/src/components/buttons/DownloadButton.tsx new file mode 100644 index 00000000000..68f8c1e7c57 --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/DownloadButton.tsx @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 { buttonStyle } from './Button'; +import { PrimaryStyle } from './ButtonPrimary'; + +export const DownloadButton = styled.a` + ${buttonStyle} + ${PrimaryStyle} + &:hover { + border-bottom-color: transparent; + } +`; diff --git a/server/sonar-web/design-system/src/components/buttons/ThirdPartyButton.tsx b/server/sonar-web/design-system/src/components/buttons/ThirdPartyButton.tsx new file mode 100644 index 00000000000..86a9e0b54ac --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/ThirdPartyButton.tsx @@ -0,0 +1,48 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 }: ThirdPartyProps) { + const size = 16; + return ( + <ThirdPartyButtonStyled {...buttonProps}> + <img alt={name} className="sw-mr-1" height={size} src={iconPath} width={size} /> + {children} + </ThirdPartyButtonStyled> + ); +} + +const ThirdPartyButtonStyled: React.FC<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/components/buttons/WrapperButton.tsx b/server/sonar-web/design-system/src/components/buttons/WrapperButton.tsx new file mode 100644 index 00000000000..64d86fc613f --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/WrapperButton.tsx @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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, themeColor } from '../../helpers'; +import { Button, ButtonProps } from './Button'; + +export const WrapperButton: React.FC<ButtonProps> = styled(Button)` + --background: none; + --backgroundHover: none; + --color: none; + --focus: ${themeColor('button', OPACITY_20_PERCENT)}; + --border: none; +`; diff --git a/server/sonar-web/design-system/src/components/__tests__/buttons-test.tsx b/server/sonar-web/design-system/src/components/buttons/__tests__/buttons-test.tsx index f2a0886ea84..e8e0007d5b7 100644 --- a/server/sonar-web/design-system/src/components/__tests__/buttons-test.tsx +++ b/server/sonar-web/design-system/src/components/buttons/__tests__/buttons-test.tsx @@ -19,8 +19,8 @@ */ import { screen } from '@testing-library/react'; -import { render } from '../../helpers/testUtils'; -import { CodeViewerExpander } from '../buttons'; +import { render } from '../../../helpers/testUtils'; +import { CodeViewerExpander } from '../BareButtons'; it('renders CodeViewerExpander correctly when direction is UP', () => { render(<CodeViewerExpander direction="UP">Hello</CodeViewerExpander>); diff --git a/server/sonar-web/design-system/src/components/buttons/index.ts b/server/sonar-web/design-system/src/components/buttons/index.ts new file mode 100644 index 00000000000..a813c49afc8 --- /dev/null +++ b/server/sonar-web/design-system/src/components/buttons/index.ts @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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. + */ +/* + * SonarQube + * Copyright (C) 2009-2023 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 './BareButtons'; +export * from './Button'; +export * from './ButtonPrimary'; +export * from './ButtonSecondary'; +export * from './DangerButtonPrimary'; +export * from './DangerButtonSecondary'; +export * from './DownloadButton'; +export * from './ThirdPartyButton'; +export * from './WrapperButton'; diff --git a/server/sonar-web/design-system/src/components/index.ts b/server/sonar-web/design-system/src/components/index.ts index 1a1f1db8ea6..d5bb51707e8 100644 --- a/server/sonar-web/design-system/src/components/index.ts +++ b/server/sonar-web/design-system/src/components/index.ts @@ -25,15 +25,11 @@ export { BarChart } from './BarChart'; export { Breadcrumbs } from './Breadcrumbs'; export * from './BubbleChart'; export * from './Card'; -export * from './Checkbox'; export * from './CodeSnippet'; export * from './CodeSyntaxHighlighter'; export * from './ColorsLegend'; export * from './CoverageIndicator'; -export * from './DatePicker'; -export * from './DateRangePicker'; export { DeferredSpinner } from './DeferredSpinner'; -export * from './DiscreetSelect'; export { ActionsDropdown, Dropdown } from './Dropdown'; export * from './DropdownMenu'; export { DropdownToggler } from './DropdownToggler'; @@ -44,17 +40,12 @@ export * from './FacetItem'; export { FailedQGConditionLink } from './FailedQGConditionLink'; export { FlagMessage } from './FlagMessage'; export * from './FlowStep'; -export * from './FormField'; export * from './GenericAvatar'; export * from './HighlightedSection'; export { Histogram } from './Histogram'; export { HotspotRating } from './HotspotRating'; export * from './HtmlFormatter'; export { IllustratedSelectionCard } from './IlllustredSelectionCard'; -export * from './InputField'; -export * from './InputMultiSelect'; -export { InputSearch } from './InputSearch'; -export * from './InputSelect'; export * from './InteractiveIcon'; export * from './IssueMessageHighlighting'; export * from './KeyboardHint'; @@ -65,15 +56,11 @@ export * from './MainAppBar'; export * from './MainMenu'; export * from './MainMenuItem'; export * from './MetricsRatingBadge'; -export * from './MultiSelectMenu'; export * from './NavBarTabs'; export * from './NewCodeLegend'; export * from './OutsideClickHandler'; export { QualityGateIndicator } from './QualityGateIndicator'; -export * from './RadioButton'; export * from './SearchHighlighter'; -export * from './SearchSelect'; -export * from './SearchSelectDropdown'; export * from './SelectionCard'; export * from './Separator'; export * from './SizeIndicator'; @@ -99,6 +86,7 @@ export * from './code-line/LineStyles'; export * from './code-line/LineToken'; export * from './code-line/LineWrapper'; export * from './icons'; +export * from './input'; export * from './layouts'; export * from './modal/Modal'; export * from './popups'; diff --git a/server/sonar-web/design-system/src/components/Checkbox.tsx b/server/sonar-web/design-system/src/components/input/Checkbox.tsx index 238a52cba6e..707cae6aa65 100644 --- a/server/sonar-web/design-system/src/components/Checkbox.tsx +++ b/server/sonar-web/design-system/src/components/input/Checkbox.tsx @@ -21,10 +21,10 @@ import styled from '@emotion/styled'; import React from 'react'; import tw from 'twin.macro'; -import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; -import { DeferredSpinner } from './DeferredSpinner'; -import { CheckIcon } from './icons/CheckIcon'; -import { CustomIcon } from './icons/Icon'; +import { themeBorder, themeColor, themeContrast } from '../../helpers/theme'; +import { DeferredSpinner } from '../DeferredSpinner'; +import { CheckIcon } from '../icons/CheckIcon'; +import { CustomIcon } from '../icons/Icon'; interface Props { checked: boolean; diff --git a/server/sonar-web/design-system/src/components/DatePicker.tsx b/server/sonar-web/design-system/src/components/input/DatePicker.tsx index 838fbd04cc0..fc8f1e7c96b 100644 --- a/server/sonar-web/design-system/src/components/DatePicker.tsx +++ b/server/sonar-web/design-system/src/components/input/DatePicker.tsx @@ -40,17 +40,17 @@ import { useDayPicker, } from 'react-day-picker'; import tw from 'twin.macro'; -import { PopupPlacement, PopupZLevel, themeBorder, themeColor, themeContrast } from '../helpers'; -import { InputSizeKeys } from '../types/theme'; -import EscKeydownHandler from './EscKeydownHandler'; -import { FocusOutHandler } from './FocusOutHandler'; +import { PopupPlacement, PopupZLevel, themeBorder, themeColor, themeContrast } from '../../helpers'; +import { InputSizeKeys } from '../../types/theme'; +import EscKeydownHandler from '../EscKeydownHandler'; +import { FocusOutHandler } from '../FocusOutHandler'; +import { InteractiveIcon } from '../InteractiveIcon'; +import { OutsideClickHandler } from '../OutsideClickHandler'; +import { CalendarIcon, ChevronLeftIcon, ChevronRightIcon } from '../icons'; +import { CloseIcon } from '../icons/CloseIcon'; +import { Popup } from '../popups'; import { InputField } from './InputField'; import { InputSelect } from './InputSelect'; -import { InteractiveIcon } from './InteractiveIcon'; -import { OutsideClickHandler } from './OutsideClickHandler'; -import { CalendarIcon, ChevronLeftIcon, ChevronRightIcon } from './icons'; -import { CloseIcon } from './icons/CloseIcon'; -import { Popup } from './popups'; // When no minDate is given, year dropdown will show year options up to PAST_MAX_YEARS in the past const YEARS_TO_DISPLAY = 10; diff --git a/server/sonar-web/design-system/src/components/DateRangePicker.tsx b/server/sonar-web/design-system/src/components/input/DateRangePicker.tsx index f44ca09e0ca..f3f65ea29c1 100644 --- a/server/sonar-web/design-system/src/components/DateRangePicker.tsx +++ b/server/sonar-web/design-system/src/components/input/DateRangePicker.tsx @@ -20,9 +20,9 @@ import classNames from 'classnames'; import { max, min } from 'date-fns'; import * as React from 'react'; -import { PopupZLevel } from '../helpers'; +import { PopupZLevel } from '../../helpers'; +import { LightLabel } from '../Text'; import { DatePicker } from './DatePicker'; -import { LightLabel } from './Text'; interface DateRange { from?: Date; diff --git a/server/sonar-web/design-system/src/components/DiscreetSelect.tsx b/server/sonar-web/design-system/src/components/input/DiscreetSelect.tsx index 085caf1b12b..543f182bb8c 100644 --- a/server/sonar-web/design-system/src/components/DiscreetSelect.tsx +++ b/server/sonar-web/design-system/src/components/input/DiscreetSelect.tsx @@ -20,8 +20,8 @@ import styled from '@emotion/styled'; import tw from 'twin.macro'; -import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; -import { InputSizeKeys } from '../types/theme'; +import { themeBorder, themeColor, themeContrast } from '../../helpers/theme'; +import { InputSizeKeys } from '../../types/theme'; import { InputSelect, LabelValueSelectOption } from './InputSelect'; interface Props<V> { diff --git a/server/sonar-web/design-system/src/components/FormField.tsx b/server/sonar-web/design-system/src/components/input/FormField.tsx index a6bac58d5e8..3397bc41381 100644 --- a/server/sonar-web/design-system/src/components/FormField.tsx +++ b/server/sonar-web/design-system/src/components/input/FormField.tsx @@ -20,8 +20,8 @@ import styled from '@emotion/styled'; import { ReactNode } from 'react'; import tw from 'twin.macro'; -import { Highlight, Note } from './Text'; -import { RequiredIcon } from './icons'; +import { Highlight, Note } from '../Text'; +import { RequiredIcon } from '../icons'; interface Props { ariaLabel?: string; diff --git a/server/sonar-web/design-system/src/components/InputField.tsx b/server/sonar-web/design-system/src/components/input/InputField.tsx index 1dab905fced..ec3ddad5a4f 100644 --- a/server/sonar-web/design-system/src/components/InputField.tsx +++ b/server/sonar-web/design-system/src/components/input/InputField.tsx @@ -21,9 +21,9 @@ import { css } from '@emotion/react'; import styled from '@emotion/styled'; import { forwardRef } from 'react'; import tw from 'twin.macro'; -import { INPUT_SIZES } from '../helpers/constants'; -import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; -import { InputSizeKeys, ThemedProps } from '../types/theme'; +import { INPUT_SIZES } from '../../helpers/constants'; +import { themeBorder, themeColor, themeContrast } from '../../helpers/theme'; +import { InputSizeKeys, ThemedProps } from '../../types/theme'; interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> { as?: React.ElementType; diff --git a/server/sonar-web/design-system/src/components/InputMultiSelect.tsx b/server/sonar-web/design-system/src/components/input/InputMultiSelect.tsx index 6a7eca741bf..6020898fbd5 100644 --- a/server/sonar-web/design-system/src/components/InputMultiSelect.tsx +++ b/server/sonar-web/design-system/src/components/input/InputMultiSelect.tsx @@ -19,11 +19,11 @@ */ import styled from '@emotion/styled'; import classNames from 'classnames'; -import { themeBorder } from '../helpers'; -import { Badge } from './Badge'; -import { LightLabel } from './Text'; -import { ButtonProps, WrapperButton } from './buttons'; -import { ChevronDownIcon } from './icons'; +import { themeBorder } from '../../helpers'; +import { Badge } from '../Badge'; +import { LightLabel } from '../Text'; +import { ButtonProps, WrapperButton } from '../buttons'; +import { ChevronDownIcon } from '../icons'; interface Props extends Pick<ButtonProps, 'onClick'> { className?: string; diff --git a/server/sonar-web/design-system/src/components/InputSearch.tsx b/server/sonar-web/design-system/src/components/input/InputSearch.tsx index 354fab3b5d2..beb1ef1ca18 100644 --- a/server/sonar-web/design-system/src/components/InputSearch.tsx +++ b/server/sonar-web/design-system/src/components/input/InputSearch.tsx @@ -23,15 +23,15 @@ import classNames from 'classnames'; import { debounce } from 'lodash'; import React, { PropsWithChildren, useEffect, useMemo, useRef, useState } from 'react'; import tw, { theme } from 'twin.macro'; -import { DEBOUNCE_DELAY, INPUT_SIZES } from '../helpers/constants'; -import { Key } from '../helpers/keyboard'; -import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; -import { isDefined } from '../helpers/types'; -import { InputSizeKeys } from '../types/theme'; -import { DeferredSpinner, Spinner } from './DeferredSpinner'; -import { InteractiveIcon } from './InteractiveIcon'; -import { CloseIcon } from './icons/CloseIcon'; -import { SearchIcon } from './icons/SearchIcon'; +import { DEBOUNCE_DELAY, INPUT_SIZES } from '../../helpers/constants'; +import { Key } from '../../helpers/keyboard'; +import { themeBorder, themeColor, themeContrast } from '../../helpers/theme'; +import { isDefined } from '../../helpers/types'; +import { InputSizeKeys } from '../../types/theme'; +import { DeferredSpinner, Spinner } from '../DeferredSpinner'; +import { InteractiveIcon } from '../InteractiveIcon'; +import { CloseIcon } from '../icons/CloseIcon'; +import { SearchIcon } from '../icons/SearchIcon'; interface Props { autoFocus?: boolean; diff --git a/server/sonar-web/design-system/src/components/InputSelect.tsx b/server/sonar-web/design-system/src/components/input/InputSelect.tsx index 4edc8e58442..586ae032180 100644 --- a/server/sonar-web/design-system/src/components/InputSelect.tsx +++ b/server/sonar-web/design-system/src/components/input/InputSelect.tsx @@ -29,11 +29,11 @@ import ReactSelect, { StylesConfig, components, } from 'react-select'; -import { INPUT_SIZES } from '../helpers'; -import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; -import { InputSizeKeys } from '../types/theme'; -import { SearchHighlighter } from './SearchHighlighter'; -import { ChevronDownIcon } from './icons'; +import { INPUT_SIZES } from '../../helpers'; +import { themeBorder, themeColor, themeContrast } from '../../helpers/theme'; +import { InputSizeKeys } from '../../types/theme'; +import { SearchHighlighter } from '../SearchHighlighter'; +import { ChevronDownIcon } from '../icons'; export interface LabelValueSelectOption<V> { Icon?: ReactNode; diff --git a/server/sonar-web/design-system/src/components/MultiSelectMenu.tsx b/server/sonar-web/design-system/src/components/input/MultiSelectMenu.tsx index ecfaa459512..191de5d27f8 100644 --- a/server/sonar-web/design-system/src/components/MultiSelectMenu.tsx +++ b/server/sonar-web/design-system/src/components/input/MultiSelectMenu.tsx @@ -20,8 +20,8 @@ import classNames from 'classnames'; import { difference } from 'lodash'; import { PureComponent } from 'react'; -import { Key } from '../helpers/keyboard'; -import { ItemDivider, ItemHeader } from './DropdownMenu'; +import { Key } from '../../helpers/keyboard'; +import { ItemDivider, ItemHeader } from '../DropdownMenu'; import { InputSearch } from './InputSearch'; import { MultiSelectMenuOption } from './MultiSelectMenuOption'; @@ -177,10 +177,12 @@ export class MultiSelectMenu extends PureComponent<Props, State> { this.props.onSelect(item); }; - onUnselectItem = (item: string) => this.props.onUnselect(item); + onUnselectItem = (item: string) => { + this.props.onUnselect(item); + }; isNewElement = (elem: string, { selectedElements, elements }: Props) => - elem.length > 0 && selectedElements.indexOf(elem) === -1 && elements.indexOf(elem) === -1; + elem.length > 0 && !selectedElements.includes(elem) && !elements.includes(elem); updateSelectedElements = (props: PropsWithDefault) => { this.setState((state: State) => { diff --git a/server/sonar-web/design-system/src/components/MultiSelectMenuOption.tsx b/server/sonar-web/design-system/src/components/input/MultiSelectMenuOption.tsx index e68dd7c3687..f801a5d062f 100644 --- a/server/sonar-web/design-system/src/components/MultiSelectMenuOption.tsx +++ b/server/sonar-web/design-system/src/components/input/MultiSelectMenuOption.tsx @@ -19,7 +19,7 @@ */ import classNames from 'classnames'; import { identity } from 'lodash'; -import { ItemCheckbox } from './DropdownMenu'; +import { ItemCheckbox } from '../DropdownMenu'; export interface MultiSelectOptionProps { active?: boolean; diff --git a/server/sonar-web/design-system/src/components/RadioButton.tsx b/server/sonar-web/design-system/src/components/input/RadioButton.tsx index 069f6d2c78f..c9748461aed 100644 --- a/server/sonar-web/design-system/src/components/RadioButton.tsx +++ b/server/sonar-web/design-system/src/components/input/RadioButton.tsx @@ -21,7 +21,7 @@ import styled from '@emotion/styled'; import classNames from 'classnames'; import React from 'react'; import tw from 'twin.macro'; -import { themeBorder, themeColor } from '../helpers/theme'; +import { themeBorder, themeColor } from '../../helpers/theme'; type AllowedRadioButtonAttributes = Pick< React.InputHTMLAttributes<HTMLInputElement>, diff --git a/server/sonar-web/design-system/src/components/SearchSelect.tsx b/server/sonar-web/design-system/src/components/input/SearchSelect.tsx index c17c22b62b6..79b654a70fa 100644 --- a/server/sonar-web/design-system/src/components/SearchSelect.tsx +++ b/server/sonar-web/design-system/src/components/input/SearchSelect.tsx @@ -23,9 +23,9 @@ import React, { RefObject } from 'react'; import { GroupBase, InputProps, components } from 'react-select'; import AsyncSelect, { AsyncProps } from 'react-select/async'; import Select from 'react-select/dist/declarations/src/Select'; -import { INPUT_SIZES } from '../helpers'; -import { Key } from '../helpers/keyboard'; -import { translate } from '../helpers/l10n'; +import { INPUT_SIZES } from '../../helpers'; +import { Key } from '../../helpers/keyboard'; +import { translate } from '../../helpers/l10n'; import { InputSearch } from './InputSearch'; import { LabelValueSelectOption, SelectProps, selectStyle } from './InputSelect'; diff --git a/server/sonar-web/design-system/src/components/SearchSelectDropdown.tsx b/server/sonar-web/design-system/src/components/input/SearchSelectDropdown.tsx index f44bff6484d..2e105e2365f 100644 --- a/server/sonar-web/design-system/src/components/SearchSelectDropdown.tsx +++ b/server/sonar-web/design-system/src/components/input/SearchSelectDropdown.tsx @@ -30,11 +30,11 @@ import { import { AsyncProps } from 'react-select/async'; import Select from 'react-select/dist/declarations/src/Select'; import tw from 'twin.macro'; -import { DEBOUNCE_DELAY, PopupPlacement, PopupZLevel, themeBorder } from '../helpers'; -import { InputSizeKeys } from '../types/theme'; -import { DropdownToggler } from './DropdownToggler'; +import { DEBOUNCE_DELAY, PopupPlacement, PopupZLevel, themeBorder } from '../../helpers'; +import { InputSizeKeys } from '../../types/theme'; +import { DropdownToggler } from '../DropdownToggler'; +import { SearchHighlighterContext } from '../SearchHighlighter'; import { IconOption, LabelValueSelectOption, SelectProps } from './InputSelect'; -import { SearchHighlighterContext } from './SearchHighlighter'; import { SearchSelect } from './SearchSelect'; import { SearchSelectDropdownControl } from './SearchSelectDropdownControl'; diff --git a/server/sonar-web/design-system/src/components/SearchSelectDropdownControl.tsx b/server/sonar-web/design-system/src/components/input/SearchSelectDropdownControl.tsx index 83873796134..7090d3c4c91 100644 --- a/server/sonar-web/design-system/src/components/SearchSelectDropdownControl.tsx +++ b/server/sonar-web/design-system/src/components/input/SearchSelectDropdownControl.tsx @@ -21,10 +21,10 @@ import styled from '@emotion/styled'; import classNames from 'classnames'; import tw from 'twin.macro'; -import { INPUT_SIZES, themeBorder, themeColor, themeContrast } from '../helpers'; -import { Key } from '../helpers/keyboard'; -import { InputSizeKeys } from '../types/theme'; -import { ChevronDownIcon } from './icons'; +import { INPUT_SIZES, themeBorder, themeColor, themeContrast } from '../../helpers'; +import { Key } from '../../helpers/keyboard'; +import { InputSizeKeys } from '../../types/theme'; +import { ChevronDownIcon } from '../icons'; interface SearchSelectDropdownControlProps { ariaLabel?: string; diff --git a/server/sonar-web/design-system/src/components/__tests__/DatePicker-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/DatePicker-test.tsx index 01aa68be4c7..81d9f167caf 100644 --- a/server/sonar-web/design-system/src/components/__tests__/DatePicker-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/DatePicker-test.tsx @@ -21,7 +21,7 @@ import { screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { getMonth, getYear, parseISO } from 'date-fns'; -import { render } from '../../helpers/testUtils'; +import { render } from '../../../helpers/testUtils'; import { DatePicker } from '../DatePicker'; it('behaves correctly', async () => { diff --git a/server/sonar-web/design-system/src/components/__tests__/DateRangePicker-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/DateRangePicker-test.tsx index 6710f23ce0a..62902dfcb1c 100644 --- a/server/sonar-web/design-system/src/components/__tests__/DateRangePicker-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/DateRangePicker-test.tsx @@ -20,7 +20,7 @@ import { screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { formatISO, parseISO } from 'date-fns'; -import { render } from '../../helpers/testUtils'; +import { render } from '../../../helpers/testUtils'; import { DateRangePicker } from '../DateRangePicker'; beforeEach(() => { diff --git a/server/sonar-web/design-system/src/components/__tests__/DiscreetSelect-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/DiscreetSelect-test.tsx index fea6a4c0cc3..7db557af2a0 100644 --- a/server/sonar-web/design-system/src/components/__tests__/DiscreetSelect-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/DiscreetSelect-test.tsx @@ -19,8 +19,8 @@ */ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { render } from '../../helpers/testUtils'; -import { FCProps } from '../../types/misc'; +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; import { DiscreetSelect } from '../DiscreetSelect'; it('should render discreet select and invoke CB on value click', async () => { diff --git a/server/sonar-web/design-system/src/components/__tests__/FormField-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/FormField-test.tsx index ee86ad31e26..a8a4faeb025 100644 --- a/server/sonar-web/design-system/src/components/__tests__/FormField-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/FormField-test.tsx @@ -20,7 +20,7 @@ import { screen } from '@testing-library/react'; import { FCProps } from '~types/misc'; -import { render } from '../../helpers/testUtils'; +import { render } from '../../../helpers/testUtils'; import { FormField } from '../FormField'; it('should render correctly', () => { diff --git a/server/sonar-web/design-system/src/components/__tests__/InputField-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/InputField-test.tsx index 47fcac116ca..47fcac116ca 100644 --- a/server/sonar-web/design-system/src/components/__tests__/InputField-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/InputField-test.tsx diff --git a/server/sonar-web/design-system/src/components/__tests__/InputMultiSelect-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/InputMultiSelect-test.tsx index d40de11ab10..d362d00db85 100644 --- a/server/sonar-web/design-system/src/components/__tests__/InputMultiSelect-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/InputMultiSelect-test.tsx @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { render, screen } from '@testing-library/react'; -import { FCProps } from '../../types/misc'; +import { FCProps } from '../../../types/misc'; import { InputMultiSelect } from '../InputMultiSelect'; it('should render correctly', () => { diff --git a/server/sonar-web/design-system/src/components/__tests__/InputSearch-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/InputSearch-test.tsx index 683c2e5fb74..fa5f5c71b73 100644 --- a/server/sonar-web/design-system/src/components/__tests__/InputSearch-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/InputSearch-test.tsx @@ -18,8 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { screen, waitFor } from '@testing-library/react'; -import { render } from '../../helpers/testUtils'; -import { FCProps } from '../../types/misc'; +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; import { InputSearch } from '../InputSearch'; it('should warn when input is too short', async () => { diff --git a/server/sonar-web/design-system/src/components/__tests__/InputSelect-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/InputSelect-test.tsx index 8d835940dfc..fefc767f86b 100644 --- a/server/sonar-web/design-system/src/components/__tests__/InputSelect-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/InputSelect-test.tsx @@ -19,8 +19,8 @@ */ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { render } from '../../helpers/testUtils'; -import { FCProps } from '../../types/misc'; +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; import { InputSelect } from '../InputSelect'; it('should render select input and be able to click and change', async () => { diff --git a/server/sonar-web/design-system/src/components/__tests__/MultiSelectMenu-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/MultiSelectMenu-test.tsx index a1c7b5800ea..a1c7b5800ea 100644 --- a/server/sonar-web/design-system/src/components/__tests__/MultiSelectMenu-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/MultiSelectMenu-test.tsx diff --git a/server/sonar-web/design-system/src/components/__tests__/RadioButton-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/RadioButton-test.tsx index deff53b4071..b84f0bc377e 100644 --- a/server/sonar-web/design-system/src/components/__tests__/RadioButton-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/RadioButton-test.tsx @@ -19,8 +19,8 @@ */ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { render } from '../../helpers/testUtils'; -import { FCProps } from '../../types/misc'; +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; import { RadioButton } from '../RadioButton'; const value = 'value'; diff --git a/server/sonar-web/design-system/src/components/__tests__/SearchSelectDropdown-test.tsx b/server/sonar-web/design-system/src/components/input/__tests__/SearchSelectDropdown-test.tsx index 18ee6f860aa..1c7d4874136 100644 --- a/server/sonar-web/design-system/src/components/__tests__/SearchSelectDropdown-test.tsx +++ b/server/sonar-web/design-system/src/components/input/__tests__/SearchSelectDropdown-test.tsx @@ -19,8 +19,8 @@ */ import { act, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { render } from '../../helpers/testUtils'; -import { FCProps } from '../../types/misc'; +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; import { LabelValueSelectOption } from '../InputSelect'; import { SearchSelectDropdown } from '../SearchSelectDropdown'; diff --git a/server/sonar-web/design-system/src/components/input/index.ts b/server/sonar-web/design-system/src/components/input/index.ts new file mode 100644 index 00000000000..ad389e9f27f --- /dev/null +++ b/server/sonar-web/design-system/src/components/input/index.ts @@ -0,0 +1,32 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 './Checkbox'; +export * from './DatePicker'; +export * from './DateRangePicker'; +export * from './DiscreetSelect'; +export * from './FormField'; +export * from './InputField'; +export * from './InputMultiSelect'; +export * from './InputSearch'; +export * from './InputSelect'; +export * from './MultiSelectMenu'; +export * from './RadioButton'; +export * from './SearchSelect'; +export * from './SearchSelectDropdown'; |