Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 40 additions & 37 deletions src/modules/Tab/Tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import PropTypes from 'prop-types'
import React from 'react'

import {
ModernAutoControlledComponent as Component,
customPropTypes,
getElementType,
getUnhandledProps,
useAutoControlledValue,
} from '../../lib'
import Grid from '../../collections/Grid/Grid'
import GridColumn from '../../collections/Grid/GridColumn'
Expand All @@ -18,21 +18,25 @@ import TabPane from './TabPane'
* @see Menu
* @see Segment
*/
class Tab extends Component {
getInitialAutoControlledState() {
return { activeIndex: 0 }
const Tab = React.forwardRef(function (props, ref) {
const { grid, menu, panes, menuPosition, renderActiveOnly } = props

const [activeIndex, setActiveIndex] = useAutoControlledValue({
state: props.activeIndex,
defaultState: props.defaultActiveIndex,
initialState: 0,
})

const handleItemClick = (e, { index }) => {
_.invoke(props, 'onTabChange', e, { ...props, activeIndex: index })
setActiveIndex(index)
}

handleItemClick = (e, { index }) => {
_.invoke(this.props, 'onTabChange', e, { ...this.props, activeIndex: index })
this.setState({ activeIndex: index })
}

renderItems() {
const { panes, renderActiveOnly } = this.props
const { activeIndex } = this.state
const renderItems = () => {
if (renderActiveOnly) {
return _.invoke(_.get(panes, `[${activeIndex}]`), 'render', props)
}

if (renderActiveOnly) return _.invoke(_.get(panes, `[${activeIndex}]`), 'render', this.props)
return _.map(panes, ({ pane }, index) =>
TabPane.create(pane, {
overrideProps: {
Expand All @@ -42,10 +46,7 @@ class Tab extends Component {
)
}

renderMenu() {
const { menu, panes, menuPosition } = this.props
const { activeIndex } = this.state

const renderMenu = () => {
if (menu.tabular === true && menuPosition === 'right') {
menu.tabular = 'right'
}
Expand All @@ -54,55 +55,57 @@ class Tab extends Component {
autoGenerateKey: false,
overrideProps: {
items: _.map(panes, 'menuItem'),
onItemClick: this.handleItemClick,
onItemClick: handleItemClick,
activeIndex,
},
})
}

renderVertical(menu) {
const { grid, menuPosition } = this.props
const renderVertical = (menuElement) => {
const { paneWidth, tabWidth, ...gridProps } = grid

const position = menuPosition || (menu.props.tabular === 'right' && 'right') || 'left'
const position = menuPosition || (menuElement.props.tabular === 'right' && 'right') || 'left'

return (
<Grid {...gridProps}>
{position === 'left' &&
GridColumn.create({ width: tabWidth, children: menu }, { autoGenerateKey: false })}
GridColumn.create({ width: tabWidth, children: menuElement }, { autoGenerateKey: false })}
{GridColumn.create(
{
width: paneWidth,
children: this.renderItems(),
children: renderItems(),
stretched: true,
},
{ autoGenerateKey: false },
)}
{position === 'right' &&
GridColumn.create({ width: tabWidth, children: menu }, { autoGenerateKey: false })}
GridColumn.create({ width: tabWidth, children: menuElement }, { autoGenerateKey: false })}
</Grid>
)
}

render() {
const menu = this.renderMenu()
const rest = getUnhandledProps(Tab, this.props)
const ElementType = getElementType(Tab, this.props)

if (menu.props.vertical) {
return <ElementType {...rest}>{this.renderVertical(menu)}</ElementType>
}
const menuElement = renderMenu()
const rest = getUnhandledProps(Tab, props)
const ElementType = getElementType(Tab, props)

if (menuElement.props.vertical) {
return (
<ElementType {...rest}>
{menu.props.attached !== 'bottom' && menu}
{this.renderItems()}
{menu.props.attached === 'bottom' && menu}
<ElementType {...rest} ref={ref}>
{renderVertical(menuElement)}
</ElementType>
)
}
}

return (
<ElementType {...rest} ref={ref}>
{menuElement.props.attached !== 'bottom' && menuElement}
{renderItems()}
{menuElement.props.attached === 'bottom' && menuElement}
</ElementType>
)
})

Tab.displayName = 'Tab'
Tab.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down
8 changes: 5 additions & 3 deletions src/modules/Tab/TabPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,32 @@ import Segment from '../../elements/Segment/Segment'
/**
* A tab pane holds the content of a tab.
*/
function TabPane(props) {
const TabPane = React.forwardRef(function (props, ref) {
const { active, children, className, content, loading } = props

const classes = cx(useKeyOnly(active, 'active'), useKeyOnly(loading, 'loading'), 'tab', className)
const rest = getUnhandledProps(TabPane, props)
const ElementType = getElementType(TabPane, props)

const calculatedDefaultProps = {}

if (ElementType === Segment) {
calculatedDefaultProps.attached = 'bottom'
}

return (
<ElementType {...calculatedDefaultProps} {...rest} className={classes}>
<ElementType {...calculatedDefaultProps} {...rest} className={classes} ref={ref}>
{childrenUtils.isNil(children) ? content : children}
</ElementType>
)
}
})

TabPane.defaultProps = {
as: Segment,
active: true,
}

TabPane.displayName = 'TabPane'
TabPane.propTypes = {
/** An element type to render as (string or function). */
as: PropTypes.elementType,
Expand Down
2 changes: 2 additions & 0 deletions test/specs/modules/Tab/Tab-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { sandbox } from 'test/utils'

describe('Tab', () => {
common.isConformant(Tab)
common.forwardsRef(Tab)
common.forwardsRef(Tab, { requiredProps: { menu: { vertical: true } } })
common.hasSubcomponents(Tab, [TabPane])

const panes = [
Expand Down
1 change: 1 addition & 0 deletions test/specs/modules/Tab/TabPane-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as common from 'test/specs/commonTests'

describe('TabPane', () => {
common.isConformant(TabPane)
common.forwardsRef(TabPane)

common.implementsCreateMethod(TabPane)

Expand Down