Skip to content

Commit

Permalink
chore(Tab): use React.forwardRef() (#4265)
Browse files Browse the repository at this point in the history
  • Loading branch information
layershifter committed Feb 18, 2022
1 parent e7037ac commit 88f4c78
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 40 deletions.
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

0 comments on commit 88f4c78

Please sign in to comment.