Skip to content

Commit

Permalink
Merge branch 'facebook:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Vishruta-Patil committed Mar 22, 2023
2 parents c08e3a7 + 3a73fdb commit 90d9c36
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 16 deletions.
Expand Up @@ -132,12 +132,9 @@ describe('Tabs', () => {
renderer.create(
<TestProviders>
<Tabs
// @ts-expect-error: for an edge-case that we didn't write types for
values={tabs.map((t, idx) => ({label: t, value: idx}))}
// @ts-expect-error: for an edge-case that we didn't write types for
defaultValue={0}>
{tabs.map((t, idx) => (
// @ts-expect-error: for an edge-case that we didn't write types for
<TabItem key={idx} value={idx}>
{t}
</TabItem>
Expand Down Expand Up @@ -199,4 +196,19 @@ describe('Tabs', () => {
);
}).not.toThrow();
});

it('allows a tab to be falsy', () => {
expect(() => {
renderer.create(
<TestProviders>
<Tabs>
<TabItem value="val1">Val1</TabItem>
{null}
{false}
{undefined}
</Tabs>
</TestProviders>,
);
}).not.toThrow();
});
});
12 changes: 7 additions & 5 deletions packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx
Expand Up @@ -5,11 +5,12 @@
* LICENSE file in the root directory of this source tree.
*/

import React, {cloneElement} from 'react';
import React, {cloneElement, type ReactElement} from 'react';
import clsx from 'clsx';
import {
useScrollPositionBlocker,
useTabs,
type TabItemProps,
} from '@docusaurus/theme-common/internal';
import useIsBrowser from '@docusaurus/useIsBrowser';
import type {Props} from '@theme/Tabs';
Expand Down Expand Up @@ -109,10 +110,11 @@ function TabContent({
children,
selectedValue,
}: Props & ReturnType<typeof useTabs>) {
// eslint-disable-next-line no-param-reassign
children = Array.isArray(children) ? children : [children];
const childTabs = (Array.isArray(children) ? children : [children]).filter(
Boolean,
) as ReactElement<TabItemProps>[];
if (lazy) {
const selectedTabItem = children.find(
const selectedTabItem = childTabs.find(
(tabItem) => tabItem.props.value === selectedValue,
);
if (!selectedTabItem) {
Expand All @@ -123,7 +125,7 @@ function TabContent({
}
return (
<div className="margin-top--md">
{children.map((tabItem, i) =>
{childTabs.map((tabItem, i) =>
cloneElement(tabItem, {
key: i,
hidden: tabItem.props.value !== selectedValue,
Expand Down
18 changes: 10 additions & 8 deletions packages/docusaurus-theme-common/src/utils/tabsUtils.tsx
Expand Up @@ -29,12 +29,12 @@ export interface TabValue {
readonly default?: boolean;
}

type TabItem = ReactElement<TabItemProps> | null | false | undefined;

export interface TabsProps {
readonly lazy?: boolean;
readonly block?: boolean;
readonly children:
| readonly ReactElement<TabItemProps>[]
| ReactElement<TabItemProps>;
readonly children: TabItem[] | TabItem;
readonly defaultValue?: string | null;
readonly values?: readonly TabValue[];
readonly groupId?: string;
Expand All @@ -55,14 +55,16 @@ export interface TabItemProps {
// A very rough duck type, but good enough to guard against mistakes while
// allowing customization
function isTabItem(
comp: ReactElement<object>,
comp: ReactElement<unknown>,
): comp is ReactElement<TabItemProps> {
return 'value' in comp.props;
const {props} = comp;
return !!props && typeof props === 'object' && 'value' in props;
}

function ensureValidChildren(children: TabsProps['children']) {
return React.Children.map(children, (child) => {
if (isValidElement(child) && isTabItem(child)) {
return (React.Children.map(children, (child) => {
// Pass falsy values through: allow conditionally not rendering a tab
if (!child || (isValidElement(child) && isTabItem(child))) {
return child;
}
// child.type.name will give non-sensical values in prod because of
Expand All @@ -73,7 +75,7 @@ function ensureValidChildren(children: TabsProps['children']) {
typeof child.type === 'string' ? child.type : child.type.name
}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`,
);
});
})?.filter(Boolean) ?? []) as ReactElement<TabItemProps>[];
}

function extractChildrenTabValues(children: TabsProps['children']): TabValue[] {
Expand Down

0 comments on commit 90d9c36

Please sign in to comment.