Skip to content

Commit

Permalink
feat(react): add vertical orientation for tabs (#496)
Browse files Browse the repository at this point in the history
  • Loading branch information
scurker authored Jan 7, 2022
1 parent 10f975c commit c221fa5
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 41 deletions.
129 changes: 93 additions & 36 deletions docs/patterns/components/Tabs/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useRef } from 'react';
import PropDocs from '../../../Demo/PropDocs';
import { Tabs, Tab, TabPanel, Code } from '@deque/cauldron-react';
import './index.css';

Expand All @@ -7,61 +8,117 @@ const Demo = () => {
const tabPanel2 = useRef(null);
const tabPanel3 = useRef(null);

const verticalTabPanel1 = useRef(null);
const verticalTabPanel2 = useRef(null);
const verticalTabPanel3 = useRef(null);

return (
<div className="TabsDemo">
<h1>Tabs</h1>
<h2>Demo</h2>
<h3>Basic Tabs</h3>
<Tabs aria-label="Basic Tabs">
<h3>Horizontal Tabs</h3>
<Tabs aria-label="Horizontal Tabs">
<Tab target={tabPanel1}>Tab 1</Tab>
<Tab target={tabPanel2}>Tab 2</Tab>
<Tab target={tabPanel3}>Tab 3</Tab>
</Tabs>
<TabPanel ref={tabPanel1}>
<p>Insert content for tab panel 1 here...</p>
<TabPanel ref={tabPanel1}>Panel for Tab 1</TabPanel>
<TabPanel ref={tabPanel2}>Panel for Tab 2</TabPanel>
<TabPanel ref={tabPanel3}>Panel for Tab 3</TabPanel>
<h4>Example</h4>
<Code language="javascript">
{`function HorizontalTabs() {
const tabRef1 = useRef()
const tabRef2 = useRef()
const tabRef3 = useRef()
return (
<>
<Tabs aria-label="Horizontal Tabs">
<Tab target={tabRef1}>Tab 1</Tab>
<Tab target={tabRef2}>Tab 2</Tab>
<Tab target={tabRef3}>Tab 3</Tab>
</Tabs>
<TabPanel ref={tabRef1}>
Panel for Tab 1
</TabPanel>
<TabPanel ref={tabPanel2}>
<p>Insert content for tab panel 2 here...</p>
<TabPanel ref={tabRef2}>
Panel for Tab 2
</TabPanel>
<TabPanel ref={tabPanel3}>
<p>Insert content for tab panel 3 here...</p>
<TabPanel ref={tabRef3}>
Panel for Tab 3
</TabPanel>
<h2>Code Sample</h2>
</>
)
}`}
</Code>
<h3>Vertical Tabs</h3>
<Tabs aria-label="Vertical Tabs" orientation="vertical">
<Tab target={verticalTabPanel1}>Tab 1</Tab>
<Tab target={verticalTabPanel2}>Tab 2</Tab>
<Tab target={verticalTabPanel3}>Tab 3</Tab>
</Tabs>
<TabPanel ref={verticalTabPanel1}>Panel for Tab 1</TabPanel>
<TabPanel ref={verticalTabPanel2}>Panel for Tab 2</TabPanel>
<TabPanel ref={verticalTabPanel3}>Panel for Tab 3</TabPanel>
<h4>Example</h4>
<Code language="javascript">
{`
import React, { useRef } from 'react';
import { Tabs, Tab, TabPanel, Code } from '@deque/cauldron-react';
import './index.css';
const Demo = () => {
const tabPanel1 = useRef(null);
const tabPanel2 = useRef(null);
const tabPanel3 = useRef(null);
{`function VerticalTabs() {
const tabRef1 = useRef()
const tabRef2 = useRef()
const tabRef3 = useRef()
return (
<div className="TabsDemo">
<h1>Tabs</h1>
<h2>Demo</h2>
<h3>Basic Tabs</h3>
<Tabs aria-label="Basic Tabs">
<Tab target={tabPanel1}>Tab 1</Tab>
<Tab target={tabPanel2}>Tab 2</Tab>
<Tab target={tabPanel3}>Tab 3</Tab>
<>
<Tabs aria-label="Vertical Tabs" orientation="vertical">
<Tab target={tabRef1}>Tab 1</Tab>
<Tab target={tabRef2}>Tab 2</Tab>
<Tab target={tabRef3}>Tab 3</Tab>
</Tabs>
<TabPanel ref={tabPanel1}>
<p>Insert content for tab panel 1 here...</p>
<TabPanel ref={tabRef1}>
Panel for Tab 1
</TabPanel>
<TabPanel ref={tabPanel2}>
<p>Insert content for tab panel 2 here...</p>
<TabPanel ref={tabRef2}>
Panel for Tab 2
</TabPanel>
<TabPanel ref={tabPanel3}>
<p>Insert content for tab panel 3 here...</p>
<TabPanel ref={tabRef3}>
Panel for Tab 3
</TabPanel>
</div>
);
};
`}
</>
)
}`}
</Code>
<div className="Demo-props">
<h2>Props</h2>
<PropDocs
docs={{
initialActiveIndex: {
type: 'number',
description: 'The initial active tab',
default: 0
},
thin: {
type: 'boolean',
description: 'Thin variant of tabs',
default: false
},
orientation: {
type: 'string',
description: 'Vertical or horizontal orientation of tabs',
default: 'horizontal'
},
onChange: {
type: 'function',
description:
'Callback function that gets invoked when the active tab changes'
}
}}
defaultProps={{
initialActiveIndex: 0,
orientation: 'horizontal'
}}
/>
</div>
</div>
);
};
Expand Down
25 changes: 22 additions & 3 deletions packages/react/src/components/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type TabsProps = {
children: React.ReactNode;
initialActiveIndex?: number;
thin?: boolean;
orientation?: 'horizontal' | 'vertical';
className?: string;
onChange?: ({
activeTabIndex,
Expand All @@ -23,6 +24,7 @@ type TabsProps = {
const Tabs = ({
children,
thin,
orientation = 'horizontal',
initialActiveIndex = 0,
className,
onChange,
Expand All @@ -46,36 +48,50 @@ const Tabs = ({
const { key } = event;
let newIndex: number = activeIndex;

let forward: string;
let backward: string;
if (orientation === 'horizontal') {
forward = 'ArrowRight';
backward = 'ArrowLeft';
} else {
forward = 'ArrowDown';
backward = 'ArrowUp';
}

switch (key) {
case 'ArrowLeft': {
case backward: {
newIndex = activeIndex - 1;

// circularity
if (newIndex === -1) {
newIndex = tabCount - 1;
}
setActiveIndex(newIndex);
event.preventDefault();
break;
}
case 'ArrowRight': {
case forward: {
newIndex = activeIndex + 1;

// circularity
if (newIndex === tabCount) {
newIndex = 0;
}
setActiveIndex(newIndex);
event.preventDefault();
break;
}
case 'Home': {
newIndex = 0;
setActiveIndex(newIndex);
event.preventDefault();
break;
}
case 'End': {
event.preventDefault();
newIndex = tabCount - 1;
setActiveIndex(newIndex);
event.preventDefault();
break;
}
}
Expand Down Expand Up @@ -124,7 +140,9 @@ const Tabs = ({
return (
<div
className={classNames('Tabs', className, {
'Tabs--thin': thin
'Tabs--thin': thin,
'Tabs--vertical': orientation === 'vertical',
'Tabs--horizontal': orientation === 'horizontal'
})}
ref={tabsRef}
>
Expand All @@ -147,6 +165,7 @@ Tabs.propTypes = {
'aria-labelledby': PropTypes.string,
initialActiveIndex: PropTypes.number,
thin: PropTypes.bool,
orientation: PropTypes.string,
className: PropTypes.string
};

Expand Down
33 changes: 31 additions & 2 deletions packages/styles/tabs.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,25 @@
width: fit-content;
}

.Tabs--vertical {
display: inline-flex;
}

.Tabs--vertical ~ .TabPanel {
vertical-align: top;
display: inline-block;
}

.Tablist {
display: flex;
flex-direction: row;
border-left: 1px solid var(--tabs-border-color);
}

.Tabs--vertical .Tablist {
flex-direction: column;
}

.Tab {
display: flex;
justify-content: center;
Expand All @@ -41,6 +54,18 @@
padding: var(--space-small);
}

.Tabs--vertical .Tab {
justify-content: flex-start;
}

.Tabs--vertical .Tab {
border-right: none;
}

.cauldron--theme-light .Tabs--vertical .Tab:last-child {
border-bottom: 1px solid var(--tabs-border-color);
}

.Tab:hover {
cursor: pointer;
background-color: var(--tab-active-background-color);
Expand All @@ -52,10 +77,14 @@
background-color: var(--tab-active-background-color);
font-weight: bold;
text-decoration: none;
box-shadow: inset 0px 4px 0px var(--tab-shadow-color);
box-shadow: inset 0 4px 0 var(--tab-shadow-color);
z-index: 1;
}

.Tabs--vertical .Tab--active {
box-shadow: inset 4px 0 0 var(--tab-shadow-color);
}

.TabPanel {
overflow-wrap: break-word;
color: var(--tabs-active-text-color);
Expand All @@ -69,7 +98,7 @@
}

.TabPanel--hidden {
display: none;
display: none !important;
}

.Tabs--thin .Tab {
Expand Down

0 comments on commit c221fa5

Please sign in to comment.