fix(theme-classic): allow tabs with number as value (#5732)

This commit is contained in:
Joshua Chen 2021-10-21 18:43:56 +08:00 committed by GitHub
parent 2398943c17
commit c2eda4aac1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 53 deletions

View file

@ -41,6 +41,6 @@ module.exports = {
// Maybe point to a fixture?
'@generated/.*': '<rootDir>/jest/emptyModule.js',
// TODO maybe use "projects" + multiple configs if we plan to add tests to another theme?
'@theme/(.*)': '@docusaurus/theme-classic/lib-next/theme/$1',
'@theme/(.*)': '@docusaurus/theme-classic/src/theme/$1',
},
};

View file

@ -9,6 +9,8 @@ import React from 'react';
import renderer from 'react-test-renderer';
import Tabs from '../index';
import TabItem from '../../TabItem';
import UserPreferencesProvider from '@theme/UserPreferencesProvider';
import {ScrollControllerProvider} from '@docusaurus/theme-common';
describe('Tabs', () => {
test('Should reject bad Tabs child', () => {
@ -54,53 +56,74 @@ describe('Tabs', () => {
test('Should accept valid Tabs config', () => {
expect(() => {
renderer.create(
<>
<Tabs>
<TabItem value="v1">Tab 1</TabItem>
<TabItem value="v2">Tab 2</TabItem>
</Tabs>
<Tabs>
<TabItem value="v1">Tab 1</TabItem>
<TabItem value="v2" default>
Tab 2
</TabItem>
</Tabs>
<Tabs defaultValue="v1">
<TabItem value="v1" label="V1">
Tab 1
</TabItem>
<TabItem value="v2" label="V2">
Tab 2
</TabItem>
</Tabs>
<Tabs
defaultValue="v1"
values={[
{value: 'v1', label: 'V1'},
{value: 'v2', label: 'V2'},
]}>
<TabItem>Tab 1</TabItem>
<TabItem>Tab 2</TabItem>
</Tabs>
<Tabs
defaultValue={null}
values={[
{value: 'v1', label: 'V1'},
{value: 'v2', label: 'V2'},
]}>
<TabItem>Tab 1</TabItem>
<TabItem>Tab 2</TabItem>
</Tabs>
<Tabs defaultValue={null}>
<TabItem value="v1" label="V1">
Tab 1
</TabItem>
<TabItem value="v2" label="V2">
Tab 2
</TabItem>
</Tabs>
</>,
<ScrollControllerProvider>
<UserPreferencesProvider>
<Tabs>
<TabItem value="v1">Tab 1</TabItem>
<TabItem value="v2">Tab 2</TabItem>
</Tabs>
<Tabs>
<TabItem value="v1">Tab 1</TabItem>
<TabItem value="v2" default>
Tab 2
</TabItem>
</Tabs>
<Tabs defaultValue="v1">
<TabItem value="v1" label="V1">
Tab 1
</TabItem>
<TabItem value="v2" label="V2">
Tab 2
</TabItem>
</Tabs>
<Tabs
defaultValue="v1"
values={[
{value: 'v1', label: 'V1'},
{value: 'v2', label: 'V2'},
]}>
<TabItem value="v1">Tab 1</TabItem>
<TabItem value="v2">Tab 2</TabItem>
</Tabs>
<Tabs
defaultValue={null}
values={[
{value: 'v1', label: 'V1'},
{value: 'v2', label: 'V2'},
]}>
<TabItem value="v1">Tab 1</TabItem>
<TabItem value="v2">Tab 2</TabItem>
</Tabs>
<Tabs defaultValue={null}>
<TabItem value="v1" label="V1">
Tab 1
</TabItem>
<TabItem value="v2" label="V2">
Tab 2
</TabItem>
</Tabs>
</UserPreferencesProvider>
</ScrollControllerProvider>,
);
}).toMatchInlineSnapshot(`[Function]`); // This is just a check that the function returns. We don't care about the actual DOM.
}).not.toThrow(); // TODO Better Jest infrastructure to mock the Layout
});
// https://github.com/facebook/docusaurus/issues/5729
test('Should accept dynamic Tabs with number values', () => {
expect(() => {
const tabs = ['Apple', 'Banana', 'Carrot'];
renderer.create(
<ScrollControllerProvider>
<UserPreferencesProvider>
<Tabs
values={tabs.map((t, idx) => ({label: t, value: idx}))}
defaultValue={0}>
{tabs.map((t, idx) => (
<TabItem value={idx}>{t}</TabItem>
))}
</Tabs>
</UserPreferencesProvider>
</ScrollControllerProvider>,
);
}).not.toThrow();
});
});

View file

@ -25,7 +25,7 @@ import styles from './styles.module.css';
// A very rough duck type, but good enough to guard against mistakes while
// allowing customization
function isTabItem(comp: ReactElement): comp is ReactElement<TabItemProps> {
return typeof comp.props.value === 'string';
return typeof comp.props.value !== 'undefined';
}
function TabsComponent(props: Props): JSX.Element {
@ -51,10 +51,7 @@ function TabsComponent(props: Props): JSX.Element {
);
});
const values =
valuesProp ??
children.map(({props: {value, label}}) => {
return {value, label};
});
valuesProp ?? children.map(({props: {value, label}}) => ({value, label}));
const dup = duplicates(values, (a, b) => a.value === b.value);
if (dup.length > 0) {
throw new Error(