]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22049 Move ToggleButton to sonar-aligned folder
authorstanislavh <stanislav.honcharov@sonarsource.com>
Mon, 29 Apr 2024 10:32:22 +0000 (12:32 +0200)
committerMatteo Mara <matteo.mara@sonarsource.com>
Tue, 30 Apr 2024 08:59:05 +0000 (10:59 +0200)
14 files changed:
server/sonar-web/design-system/src/components/Tabs.tsx
server/sonar-web/design-system/src/components/ToggleButton.tsx [deleted file]
server/sonar-web/design-system/src/components/__tests__/ToggleButton-test.tsx [deleted file]
server/sonar-web/design-system/src/components/index.ts
server/sonar-web/design-system/src/helpers/__tests__/tabs-test.ts [deleted file]
server/sonar-web/design-system/src/helpers/index.ts
server/sonar-web/design-system/src/helpers/tabs.ts [deleted file]
server/sonar-web/design-system/src/sonar-aligned/components/ToggleButton.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/__tests__/ToggleButton-test.tsx [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/components/index.ts
server/sonar-web/design-system/src/sonar-aligned/helpers/__tests__/tabs-test.ts [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/helpers/index.ts [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/helpers/tabs.ts [new file with mode: 0644]
server/sonar-web/design-system/src/sonar-aligned/index.ts

index 21a7fa765c8721755d51fa50726529f243c2b23b..aec59acd20a9756dd81ecf3f251c5d5e266fd4aa 100644 (file)
@@ -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 (file)
index 4c6b266..0000000
+++ /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<T extends ToggleButtonValueType> {
-  counter?: number;
-  disabled?: boolean;
-  label: string | React.ReactNode;
-  value: T;
-}
-
-export interface ButtonToggleProps<T extends ToggleButtonValueType> {
-  disabled?: boolean;
-  label?: string;
-  onChange: (value: T) => void;
-  options: ReadonlyArray<ToggleButtonsOption<T>>;
-  role?: 'radiogroup' | 'tablist';
-  value?: T;
-}
-
-export function ToggleButton<T extends ToggleButtonValueType>(props: ButtonToggleProps<T>) {
-  const { disabled = false, label, options, value, role = 'radiogroup' } = props;
-  const isRadioGroup = role === 'radiogroup';
-
-  return (
-    <Wrapper aria-label={label} role={role}>
-      {options.map((option) => (
-        <OptionButton
-          aria-checked={isRadioGroup ? option.value === value : undefined}
-          aria-controls={isRadioGroup ? undefined : getTabPanelId(String(option.value))}
-          aria-current={option.value === value}
-          data-value={option.value}
-          disabled={disabled || option.disabled}
-          id={getTabId(String(option.value))}
-          key={option.value.toString()}
-          onClick={() => {
-            if (option.value !== value) {
-              props.onChange(option.value);
-            }
-          }}
-          role={isRadioGroup ? 'radio' : 'tab'}
-          selected={option.value === value}
-        >
-          {option.label}
-          {option.counter ? (
-            <Badge className="sw-ml-1" variant="counter">
-              {option.counter}
-            </Badge>
-          ) : null}
-        </OptionButton>
-      ))}
-    </Wrapper>
-  );
-}
-
-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 (file)
index f28e9ad..0000000
+++ /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<ToggleButtonsOption<number>> = [
-    { 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<ToggleButtonsOption<number>> = [
-    { 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<FCProps<typeof ToggleButton>> = {}) {
-  return render(<ToggleButton onChange={jest.fn()} options={[]} {...props} />);
-}
index e94ac812c9e149b0fb1d66c845ac394e79ffbc4f..83d92d655d71c523aac0bb8395298ad115930c3a 100644 (file)
@@ -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 (file)
index da50632..0000000
+++ /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');
-});
index a648aef78c4dd76aed5a7b0875def02703420a9e..73dd1464b22ae56b6b5646e441c00e02bcac78b8 100644 (file)
@@ -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 (file)
index 74c3061..0000000
+++ /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 (file)
index 0000000..ab0152f
--- /dev/null
@@ -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<T extends ToggleButtonValueType> {
+  counter?: number;
+  disabled?: boolean;
+  label: string | React.ReactNode;
+  value: T;
+}
+
+export interface ButtonToggleProps<T extends ToggleButtonValueType> {
+  disabled?: boolean;
+  label?: string;
+  onChange: (value: T) => void;
+  options: ReadonlyArray<ToggleButtonsOption<T>>;
+  role?: 'radiogroup' | 'tablist';
+  value?: T;
+}
+
+export function ToggleButton<T extends ToggleButtonValueType>(props: ButtonToggleProps<T>) {
+  const { disabled = false, label, options, value, role = 'radiogroup' } = props;
+  const isRadioGroup = role === 'radiogroup';
+
+  return (
+    <Wrapper aria-label={label} role={role}>
+      {options.map((option) => (
+        <OptionButton
+          aria-checked={isRadioGroup ? option.value === value : undefined}
+          aria-controls={isRadioGroup ? undefined : getTabPanelId(String(option.value))}
+          aria-current={option.value === value}
+          data-value={option.value}
+          disabled={disabled || option.disabled}
+          id={getTabId(String(option.value))}
+          key={option.value.toString()}
+          onClick={() => {
+            if (option.value !== value) {
+              props.onChange(option.value);
+            }
+          }}
+          role={isRadioGroup ? 'radio' : 'tab'}
+          selected={option.value === value}
+        >
+          {option.label}
+          {option.counter ? (
+            <Badge className="sw-ml-1" variant="counter">
+              {option.counter}
+            </Badge>
+          ) : null}
+        </OptionButton>
+      ))}
+    </Wrapper>
+  );
+}
+
+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 (file)
index 0000000..7b07cba
--- /dev/null
@@ -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<ToggleButtonsOption<number>> = [
+    { 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<ToggleButtonsOption<number>> = [
+    { 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<FCProps<typeof ToggleButton>> = {}) {
+  return render(<ToggleButton onChange={jest.fn()} options={[]} {...props} />);
+}
index 9ffeb585803a97c6b619f43e2efeb94d05a4b1e2..edbf22d1b666d5ee73e9dd2d08329a54acd7dcfe 100644 (file)
@@ -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 (file)
index 0000000..da50632
--- /dev/null
@@ -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 (file)
index 0000000..863797b
--- /dev/null
@@ -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 (file)
index 0000000..74c3061
--- /dev/null
@@ -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}`;
+}
index 48fc39c2122a0b5e055eac728204fd63b1f6a2bb..380e82087fbb82fc5aad568d6696a155c5c49057 100644 (file)
@@ -19,4 +19,5 @@
  */
 
 export * from './components';
+export * from './helpers';
 export * from './types';