Skip to content

Commit

Permalink
refactor: TabPane is a element (#279)
Browse files Browse the repository at this point in the history
* refactor: TabPane is a element

* clean up
  • Loading branch information
zombieJ authored Jun 3, 2020
1 parent 80af6ad commit d124a62
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 82 deletions.
31 changes: 22 additions & 9 deletions src/TabPanelList/TabPane.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
import * as React from 'react';
import classNames from 'classnames';
import { Tab } from '../interface';

export interface TabPaneProps {
prefixCls: string;
id: string;
tab: Tab;
animated: boolean;
active: boolean;
tab?: React.ReactNode;
className?: string;
style?: React.CSSProperties;
disabled?: boolean;
children?: React.ReactNode;
forceRender?: boolean;
closable?: boolean;
closeIcon?: React.ReactNode;

// Pass by TabPaneList
prefixCls?: string;
tabKey?: string;
id?: string;
animated?: boolean;
active?: boolean;
destroyInactiveTabPane?: boolean;
}

export default function TabPane({
prefixCls,
forceRender,
className,
style,
id,
active,
animated,
destroyInactiveTabPane,
tab: { key, children, forceRender, className, style },
tabKey,
children,
}: TabPaneProps) {
const [visited, setVisited] = React.useState(forceRender);

Expand All @@ -40,10 +53,10 @@ export default function TabPane({

return (
<div
id={id && `${id}-panel-${key}`}
id={id && `${id}-panel-${tabKey}`}
role="tabpanel"
tabIndex={active ? 0 : -1}
aria-labelledby={id && `${id}-tab-${key}`}
aria-labelledby={id && `${id}-tab-${tabKey}`}
aria-hidden={!active}
style={{ ...mergedStyle, ...style }}
className={classNames(
Expand Down
21 changes: 9 additions & 12 deletions src/TabPanelList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';
import classNames from 'classnames';
import TabPane from './TabPane';
import TabContext from '../TabContext';
import { TabPosition, AnimatedConfig } from '../interface';

Expand Down Expand Up @@ -37,17 +36,15 @@ export default function TabPanelList({
}
>
{tabs.map(tab => {
return (
<TabPane
prefixCls={prefixCls}
id={id}
animated={tabPaneAnimated}
destroyInactiveTabPane={destroyInactiveTabPane}
active={tab.key === activeKey}
key={tab.key}
tab={tab}
/>
);
return React.cloneElement(tab.node, {
key: tab.key,
prefixCls,
tabKey: tab.key,
id,
animated: tabPaneAnimated,
active: tab.key === activeKey,
destroyInactiveTabPane,
});
})}
</div>
</div>
Expand Down
26 changes: 16 additions & 10 deletions src/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import { useEffect, useState } from 'react';
import classNames from 'classnames';
import toArray from 'rc-util/lib/Children/toArray';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import TabPane, { TabPaneProps } from './sugar/TabPane';
import TabNavList from './TabNavList';
import TabPanelList from './TabPanelList';
import TabPane, { TabPaneProps } from './TabPanelList/TabPane';
import {
Tab,
TabPosition,
RenderTabBar,
TabsLocale,
EditableConfig,
AnimatedConfig,
OnTabScroll,
Tab,
} from './interface';
import TabContext from './TabContext';
import { isMobile } from './hooks/useTouchMove';
Expand Down Expand Up @@ -66,14 +66,20 @@ export interface TabsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'o
}

function parseTabList(children: React.ReactNode): Tab[] {
return toArray(children).map((node: React.ReactElement<TabPaneProps>) =>
React.isValidElement(node)
? {
key: node.key !== undefined ? String(node.key) : undefined,
return toArray(children)
.map((node: React.ReactElement<TabPaneProps>) => {
if (React.isValidElement(node)) {
const key = node.key !== undefined ? String(node.key) : undefined;
return {
key,
...node.props,
}
: null,
);
node,
};
}

return null;
})
.filter(tab => tab);
}

function Tabs(
Expand Down Expand Up @@ -156,7 +162,7 @@ function Tabs(
// Async generate id to avoid ssr mapping failed
useEffect(() => {
if (!id) {
setMergedId(`rc-tabs-${uuid}`);
setMergedId(`rc-tabs-${process.env.NODE_ENV === 'test' ? 'test' : uuid}`);
uuid += 1;
}
}, []);
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Tabs, { TabsProps } from './Tabs';
import TabPane from './sugar/TabPane';
import TabPane, { TabPaneProps } from './TabPanelList/TabPane';

export { TabPane, TabsProps };
export { TabPane, TabsProps, TabPaneProps };

export default Tabs;
6 changes: 2 additions & 4 deletions src/interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TabPaneProps } from './sugar/TabPane';
import { TabPaneProps } from './TabPanelList/TabPane';

export type TabSizeMap = Map<
React.Key,
Expand All @@ -17,10 +17,8 @@ export type TabOffsetMap = Map<React.Key, TabOffset>;
export type TabPosition = 'left' | 'right' | 'top' | 'bottom';

export interface Tab extends TabPaneProps {
tab?: React.ReactNode;
children?: React.ReactNode;
forceRender?: boolean;
key: string;
node: React.ReactElement;
}

export type RenderTabBar = (props: any, DefaultTabBar: React.ComponentType) => React.ReactElement;
Expand Down
17 changes: 0 additions & 17 deletions src/sugar/TabPane.tsx

This file was deleted.

98 changes: 84 additions & 14 deletions tests/__snapshots__/index.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,32 @@ exports[`Tabs.Basic Normal 1`] = `
style="transform: translate(0px, 0px);"
>
<button
aria-controls="rc-tabs-0-panel-light"
aria-controls="rc-tabs-test-panel-light"
aria-selected="false"
class="rc-tabs-tab"
id="rc-tabs-0-tab-light"
id="rc-tabs-test-tab-light"
role="tab"
tabindex="0"
type="button"
>
light
</button>
<button
aria-controls="rc-tabs-0-panel-bamboo"
aria-controls="rc-tabs-test-panel-bamboo"
aria-selected="true"
class="rc-tabs-tab rc-tabs-tab-active"
id="rc-tabs-0-tab-bamboo"
id="rc-tabs-test-tab-bamboo"
role="tab"
tabindex="0"
type="button"
>
bamboo
</button>
<button
aria-controls="rc-tabs-0-panel-cute"
aria-controls="rc-tabs-test-panel-cute"
aria-selected="false"
class="rc-tabs-tab"
id="rc-tabs-0-tab-cute"
id="rc-tabs-test-tab-cute"
role="tab"
tabindex="0"
type="button"
Expand All @@ -57,12 +57,12 @@ exports[`Tabs.Basic Normal 1`] = `
class="rc-tabs-nav-operations rc-tabs-nav-operations-hidden"
>
<button
aria-controls="rc-tabs-0-more-popup"
aria-controls="rc-tabs-test-more-popup"
aria-expanded="false"
aria-haspopup="listbox"
aria-hidden="true"
class="rc-tabs-nav-more"
id="rc-tabs-0-more"
id="rc-tabs-test-more"
style="visibility: hidden; order: 1;"
tabindex="-1"
type="button"
Expand All @@ -79,28 +79,28 @@ exports[`Tabs.Basic Normal 1`] = `
>
<div
aria-hidden="true"
aria-labelledby="rc-tabs-0-tab-light"
aria-labelledby="rc-tabs-test-tab-light"
class="rc-tabs-tabpane"
id="rc-tabs-0-panel-light"
id="rc-tabs-test-panel-light"
role="tabpanel"
style="display: none;"
tabindex="-1"
/>
<div
aria-hidden="false"
aria-labelledby="rc-tabs-0-tab-bamboo"
aria-labelledby="rc-tabs-test-tab-bamboo"
class="rc-tabs-tabpane rc-tabs-tabpane-active"
id="rc-tabs-0-panel-bamboo"
id="rc-tabs-test-panel-bamboo"
role="tabpanel"
tabindex="0"
>
Bamboo
</div>
<div
aria-hidden="true"
aria-labelledby="rc-tabs-0-tab-cute"
aria-labelledby="rc-tabs-test-tab-cute"
class="rc-tabs-tabpane"
id="rc-tabs-0-panel-cute"
id="rc-tabs-test-panel-cute"
role="tabpanel"
style="display: none;"
tabindex="-1"
Expand All @@ -109,3 +109,73 @@ exports[`Tabs.Basic Normal 1`] = `
</div>
</div>
`;

exports[`Tabs.Basic Skip invalidate children 1`] = `
<div
class="rc-tabs rc-tabs-top"
>
<div
class="rc-tabs-nav"
role="tablist"
>
<div
class="rc-tabs-nav-wrap"
>
<div
class="rc-tabs-nav-list"
style="transform: translate(0px, 0px);"
>
<button
aria-controls="rc-tabs-test-panel-light"
aria-selected="true"
class="rc-tabs-tab rc-tabs-tab-active"
id="rc-tabs-test-tab-light"
role="tab"
tabindex="0"
type="button"
>
light
</button>
<div
class="rc-tabs-ink-bar rc-tabs-ink-bar-animated"
/>
</div>
</div>
<div
class="rc-tabs-nav-operations rc-tabs-nav-operations-hidden"
>
<button
aria-controls="rc-tabs-test-more-popup"
aria-expanded="false"
aria-haspopup="listbox"
aria-hidden="true"
class="rc-tabs-nav-more"
id="rc-tabs-test-more"
style="visibility: hidden; order: 1;"
tabindex="-1"
type="button"
>
More
</button>
</div>
</div>
<div
class="rc-tabs-content-holder"
>
<div
class="rc-tabs-content rc-tabs-content-top"
>
<div
aria-hidden="false"
aria-labelledby="rc-tabs-test-tab-light"
class="rc-tabs-tabpane rc-tabs-tabpane-active"
id="rc-tabs-test-panel-light"
role="tabpanel"
tabindex="0"
>
Light
</div>
</div>
</div>
</div>
`;
4 changes: 2 additions & 2 deletions tests/__snapshots__/overflow.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

exports[`Tabs.Overflow should collapse 1`] = `
<button
aria-controls="rc-tabs-0-more-popup"
aria-controls="rc-tabs-test-more-popup"
aria-expanded="false"
aria-haspopup="listbox"
aria-hidden="true"
class="rc-tabs-nav-more"
id="rc-tabs-0-more"
id="rc-tabs-test-more"
style=""
tabindex="-1"
type="button"
Expand Down
3 changes: 0 additions & 3 deletions tests/__snapshots__/suger.test.tsx.snap

This file was deleted.

16 changes: 16 additions & 0 deletions tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ describe('Tabs.Basic', () => {
expect(wrapper.render()).toMatchSnapshot();
});

it('Skip invalidate children', () => {
const wrapper = mount(
getTabs({
children: [
<TabPane tab="light" key="light">
Light
</TabPane>,
'not me',
],
}),
);
wrapper.update();

expect(wrapper.render()).toMatchSnapshot();
});

it('nothing for empty tabs', () => {
mount(getTabs({ children: null }));
});
Expand Down
Loading

1 comment on commit d124a62

@vercel
Copy link

@vercel vercel bot commented on d124a62 Jun 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.