From: stanislavh Date: Mon, 29 Apr 2024 10:32:22 +0000 (+0200) Subject: SONAR-22049 Move ToggleButton to sonar-aligned folder X-Git-Tag: 10.6.0.92116~155 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=7067c5cd8c035cb83bde3562f01462d44a768133;p=sonarqube.git SONAR-22049 Move ToggleButton to sonar-aligned folder --- diff --git a/server/sonar-web/design-system/src/components/Tabs.tsx b/server/sonar-web/design-system/src/components/Tabs.tsx index 21a7fa765c8..aec59acd20a 100644 --- a/server/sonar-web/design-system/src/components/Tabs.tsx +++ b/server/sonar-web/design-system/src/components/Tabs.tsx @@ -21,8 +21,8 @@ import styled from '@emotion/styled'; 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 { getTabId, getTabPanelId } from '../sonar-aligned/helpers/tabs'; import { Badge } from './Badge'; type TabValueType = string | number | boolean; diff --git a/server/sonar-web/design-system/src/components/ToggleButton.tsx b/server/sonar-web/design-system/src/components/ToggleButton.tsx deleted file mode 100644 index 4c6b266b91d..00000000000 --- a/server/sonar-web/design-system/src/components/ToggleButton.tsx +++ /dev/null @@ -1,120 +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 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'; - -type ToggleButtonValueType = string | number | boolean; - -export interface ToggleButtonsOption { - counter?: number; - disabled?: boolean; - label: string | React.ReactNode; - value: T; -} - -export interface ButtonToggleProps { - disabled?: boolean; - label?: string; - onChange: (value: T) => void; - options: ReadonlyArray>; - role?: 'radiogroup' | 'tablist'; - value?: T; -} - -export function ToggleButton(props: ButtonToggleProps) { - const { disabled = false, label, options, value, role = 'radiogroup' } = props; - const isRadioGroup = role === 'radiogroup'; - - return ( - - {options.map((option) => ( - { - if (option.value !== value) { - props.onChange(option.value); - } - }} - role={isRadioGroup ? 'radio' : 'tab'} - selected={option.value === value} - > - {option.label} - {option.counter ? ( - - {option.counter} - - ) : null} - - ))} - - ); -} - -const Wrapper = styled.div` - border: ${themeBorder('default', 'toggleBorder')}; - - ${tw`sw-inline-flex`} - ${tw`sw-h-control`} - ${tw`sw-box-border`} - ${tw`sw-font-semibold`} - ${tw`sw-rounded-2`} -`; - -const OptionButton = styled(ButtonSecondary)<{ selected: boolean }>` - background: ${(props) => (props.selected ? themeColor('toggleHover') : themeColor('toggle'))}; - color: ${(props) => (props.selected ? themeContrast('toggleHover') : themeContrast('toggle'))}; - border: none; - height: auto; - ${tw`sw-rounded-0`}; - ${tw`sw-truncate`}; - - &:first-of-type { - ${tw`sw-rounded-l-2`}; - } - - &:last-of-type { - ${tw`sw-rounded-r-2`}; - } - - &:not(:last-of-type) { - border-right: ${themeBorder('default', 'toggleBorder')}; - } - - &:hover { - background: ${themeColor('toggleHover')}; - color: ${themeContrast('toggleHover')}; - } - - &:focus, - &:active { - outline: ${themeBorder('focus', 'toggleFocus')}; - z-index: 1; - } -`; diff --git a/server/sonar-web/design-system/src/components/__tests__/ToggleButton-test.tsx b/server/sonar-web/design-system/src/components/__tests__/ToggleButton-test.tsx deleted file mode 100644 index f28e9ad443d..00000000000 --- a/server/sonar-web/design-system/src/components/__tests__/ToggleButton-test.tsx +++ /dev/null @@ -1,66 +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 { screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { getTabPanelId } from '../../helpers'; -import { render } from '../../helpers/testUtils'; -import { FCProps } from '../../types/misc'; -import { ToggleButton, ToggleButtonsOption } from '../ToggleButton'; - -it('should render all options', async () => { - const user = userEvent.setup(); - const onChange = jest.fn(); - const options: Array> = [ - { value: 1, label: 'first' }, - { value: 2, label: 'disabled', disabled: true }, - { value: 3, label: 'has counter', counter: 7 }, - ]; - renderToggleButtons({ onChange, options, value: 1 }); - - expect(screen.getAllByRole('radio')).toHaveLength(3); - - await user.click(screen.getByText('first')); - - expect(onChange).not.toHaveBeenCalled(); - - await user.click(screen.getByText('has counter')); - - expect(onChange).toHaveBeenCalledWith(3); -}); - -it('should work in tablist mode', () => { - const onChange = jest.fn(); - const options: Array> = [ - { value: 1, label: 'first' }, - { value: 2, label: 'second' }, - { value: 3, label: 'third' }, - ]; - renderToggleButtons({ onChange, options, value: 1, role: 'tablist' }); - - expect(screen.getAllByRole('tab')).toHaveLength(3); - expect(screen.getByRole('tab', { name: 'second' })).toHaveAttribute( - 'aria-controls', - getTabPanelId(2), - ); -}); - -function renderToggleButtons(props: Partial> = {}) { - return render(); -} diff --git a/server/sonar-web/design-system/src/components/index.ts b/server/sonar-web/design-system/src/components/index.ts index e94ac812c9e..83d92d655d7 100644 --- a/server/sonar-web/design-system/src/components/index.ts +++ b/server/sonar-web/design-system/src/components/index.ts @@ -75,7 +75,6 @@ export * from './Tags'; export * from './Text'; export * from './TextAccordion'; export * from './Title'; -export * from './ToggleButton'; export { Tooltip } from './Tooltip'; export { TopBar } from './TopBar'; export * from './TreeMap'; diff --git a/server/sonar-web/design-system/src/helpers/__tests__/tabs-test.ts b/server/sonar-web/design-system/src/helpers/__tests__/tabs-test.ts deleted file mode 100644 index da506329566..00000000000 --- a/server/sonar-web/design-system/src/helpers/__tests__/tabs-test.ts +++ /dev/null @@ -1,25 +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 { getTabId, getTabPanelId } from '../tabs'; - -it('should correctly generate IDs', () => { - expect(getTabId('ID')).toBe('tab-ID'); - expect(getTabPanelId('ID')).toBe('tabpanel-ID'); -}); diff --git a/server/sonar-web/design-system/src/helpers/index.ts b/server/sonar-web/design-system/src/helpers/index.ts index a648aef78c4..73dd1464b22 100644 --- a/server/sonar-web/design-system/src/helpers/index.ts +++ b/server/sonar-web/design-system/src/helpers/index.ts @@ -21,5 +21,4 @@ export * from './colors'; export * from './constants'; export * from './keyboard'; export * from './positioning'; -export * from './tabs'; export * from './theme'; diff --git a/server/sonar-web/design-system/src/helpers/tabs.ts b/server/sonar-web/design-system/src/helpers/tabs.ts deleted file mode 100644 index 74c306100d7..00000000000 --- a/server/sonar-web/design-system/src/helpers/tabs.ts +++ /dev/null @@ -1,26 +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. - */ -export function getTabPanelId(key: string | number) { - return `tabpanel-${key}`; -} - -export function getTabId(key: string | number) { - return `tab-${key}`; -} diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/ToggleButton.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/ToggleButton.tsx new file mode 100644 index 00000000000..ab0152f38a3 --- /dev/null +++ b/server/sonar-web/design-system/src/sonar-aligned/components/ToggleButton.tsx @@ -0,0 +1,120 @@ +/* + * 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 tw from 'twin.macro'; +import { Badge } from '../../components/Badge'; +import { themeBorder, themeColor, themeContrast } from '../../helpers/theme'; +import { getTabId, getTabPanelId } from '../helpers/tabs'; +import { ButtonSecondary } from './buttons'; + +type ToggleButtonValueType = string | number | boolean; + +export interface ToggleButtonsOption { + counter?: number; + disabled?: boolean; + label: string | React.ReactNode; + value: T; +} + +export interface ButtonToggleProps { + disabled?: boolean; + label?: string; + onChange: (value: T) => void; + options: ReadonlyArray>; + role?: 'radiogroup' | 'tablist'; + value?: T; +} + +export function ToggleButton(props: ButtonToggleProps) { + const { disabled = false, label, options, value, role = 'radiogroup' } = props; + const isRadioGroup = role === 'radiogroup'; + + return ( + + {options.map((option) => ( + { + if (option.value !== value) { + props.onChange(option.value); + } + }} + role={isRadioGroup ? 'radio' : 'tab'} + selected={option.value === value} + > + {option.label} + {option.counter ? ( + + {option.counter} + + ) : null} + + ))} + + ); +} + +const Wrapper = styled.div` + border: ${themeBorder('default', 'toggleBorder')}; + + ${tw`sw-inline-flex`} + ${tw`sw-h-control`} + ${tw`sw-box-border`} + ${tw`sw-font-semibold`} + ${tw`sw-rounded-2`} +`; + +const OptionButton = styled(ButtonSecondary)<{ selected: boolean }>` + background: ${(props) => (props.selected ? themeColor('toggleHover') : themeColor('toggle'))}; + color: ${(props) => (props.selected ? themeContrast('toggleHover') : themeContrast('toggle'))}; + border: none; + height: auto; + ${tw`sw-rounded-0`}; + ${tw`sw-truncate`}; + + &:first-of-type { + ${tw`sw-rounded-l-2`}; + } + + &:last-of-type { + ${tw`sw-rounded-r-2`}; + } + + &:not(:last-of-type) { + border-right: ${themeBorder('default', 'toggleBorder')}; + } + + &:hover { + background: ${themeColor('toggleHover')}; + color: ${themeContrast('toggleHover')}; + } + + &:focus, + &:active { + outline: ${themeBorder('focus', 'toggleFocus')}; + z-index: 1; + } +`; diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/__tests__/ToggleButton-test.tsx b/server/sonar-web/design-system/src/sonar-aligned/components/__tests__/ToggleButton-test.tsx new file mode 100644 index 00000000000..7b07cba3ff9 --- /dev/null +++ b/server/sonar-web/design-system/src/sonar-aligned/components/__tests__/ToggleButton-test.tsx @@ -0,0 +1,66 @@ +/* + * 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 { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; +import { getTabPanelId } from '../../helpers'; +import { ToggleButton, ToggleButtonsOption } from '../ToggleButton'; + +it('should render all options', async () => { + const user = userEvent.setup(); + const onChange = jest.fn(); + const options: Array> = [ + { value: 1, label: 'first' }, + { value: 2, label: 'disabled', disabled: true }, + { value: 3, label: 'has counter', counter: 7 }, + ]; + renderToggleButtons({ onChange, options, value: 1 }); + + expect(screen.getAllByRole('radio')).toHaveLength(3); + + await user.click(screen.getByText('first')); + + expect(onChange).not.toHaveBeenCalled(); + + await user.click(screen.getByText('has counter')); + + expect(onChange).toHaveBeenCalledWith(3); +}); + +it('should work in tablist mode', () => { + const onChange = jest.fn(); + const options: Array> = [ + { value: 1, label: 'first' }, + { value: 2, label: 'second' }, + { value: 3, label: 'third' }, + ]; + renderToggleButtons({ onChange, options, value: 1, role: 'tablist' }); + + expect(screen.getAllByRole('tab')).toHaveLength(3); + expect(screen.getByRole('tab', { name: 'second' })).toHaveAttribute( + 'aria-controls', + getTabPanelId(2), + ); +}); + +function renderToggleButtons(props: Partial> = {}) { + return render(); +} diff --git a/server/sonar-web/design-system/src/sonar-aligned/components/index.ts b/server/sonar-web/design-system/src/sonar-aligned/components/index.ts index 9ffeb585803..edbf22d1b66 100644 --- a/server/sonar-web/design-system/src/sonar-aligned/components/index.ts +++ b/server/sonar-web/design-system/src/sonar-aligned/components/index.ts @@ -22,5 +22,6 @@ export * from './Card'; export { DismissableFlagMessage, FlagMessage } from './FlagMessage'; export * from './MetricsRatingBadge'; export * from './Table'; +export * from './ToggleButton'; export * from './buttons'; export * from './typography'; diff --git a/server/sonar-web/design-system/src/sonar-aligned/helpers/__tests__/tabs-test.ts b/server/sonar-web/design-system/src/sonar-aligned/helpers/__tests__/tabs-test.ts new file mode 100644 index 00000000000..da506329566 --- /dev/null +++ b/server/sonar-web/design-system/src/sonar-aligned/helpers/__tests__/tabs-test.ts @@ -0,0 +1,25 @@ +/* + * 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 { getTabId, getTabPanelId } from '../tabs'; + +it('should correctly generate IDs', () => { + expect(getTabId('ID')).toBe('tab-ID'); + expect(getTabPanelId('ID')).toBe('tabpanel-ID'); +}); diff --git a/server/sonar-web/design-system/src/sonar-aligned/helpers/index.ts b/server/sonar-web/design-system/src/sonar-aligned/helpers/index.ts new file mode 100644 index 00000000000..863797b2d1f --- /dev/null +++ b/server/sonar-web/design-system/src/sonar-aligned/helpers/index.ts @@ -0,0 +1,21 @@ +/* + * 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 './tabs'; diff --git a/server/sonar-web/design-system/src/sonar-aligned/helpers/tabs.ts b/server/sonar-web/design-system/src/sonar-aligned/helpers/tabs.ts new file mode 100644 index 00000000000..74c306100d7 --- /dev/null +++ b/server/sonar-web/design-system/src/sonar-aligned/helpers/tabs.ts @@ -0,0 +1,26 @@ +/* + * 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 function getTabPanelId(key: string | number) { + return `tabpanel-${key}`; +} + +export function getTabId(key: string | number) { + return `tab-${key}`; +} diff --git a/server/sonar-web/design-system/src/sonar-aligned/index.ts b/server/sonar-web/design-system/src/sonar-aligned/index.ts index 48fc39c2122..380e82087fb 100644 --- a/server/sonar-web/design-system/src/sonar-aligned/index.ts +++ b/server/sonar-web/design-system/src/sonar-aligned/index.ts @@ -19,4 +19,5 @@ */ export * from './components'; +export * from './helpers'; export * from './types';