diff --git a/packages/terra-framework-docs/CHANGELOG.md b/packages/terra-framework-docs/CHANGELOG.md index 4a631623214..25599fdc991 100644 --- a/packages/terra-framework-docs/CHANGELOG.md +++ b/packages/terra-framework-docs/CHANGELOG.md @@ -17,6 +17,9 @@ * Updates examples for `terra-data-grid` to cover scenarios for focusable elements prevented from receiving focus. * Updated focusable cell test for `terra-data-grid` to account for focusable elements in a hidden container. +* Added + * Added example for vertical orientation functionality for `terra-tabs`. + ## 1.40.0 - (October 11, 2023) * Added diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/Tabs.1.doc.mdx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/Tabs.1.doc.mdx index a045e06b4c6..9975f7b6ab1 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/Tabs.1.doc.mdx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/Tabs.1.doc.mdx @@ -14,6 +14,7 @@ import AddTab from './example/AddTab?dev-site-example' import ClosableTab from './example/ClosableTab?dev-site-example' import AddCloseTab from './example/AddCloseTab?dev-site-example' import AddCloseTabInteractive from './example/AddCloseTabInteractive?dev-site-example' +import VerticalTabs from './example/VerticalTabs?dev-site-example' @@ -93,6 +94,7 @@ import Tabs from 'terra-tabs'; + ## Tabs Props Table diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddCloseTab.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddCloseTab.jsx index 5b4def342e7..84f3fd1243a 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddCloseTab.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddCloseTab.jsx @@ -100,7 +100,7 @@ const AddCloseTab = () => { return (
- + { tabs.map((tab) => ( diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddCloseTabInteractive.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddCloseTabInteractive.jsx index 9e5bcb785f7..c233e99adad 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddCloseTabInteractive.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddCloseTabInteractive.jsx @@ -136,7 +136,7 @@ const AddCloseTabInteractive = () => { return (
- + { tabs.map((tab) => ( diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddTab.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddTab.jsx index 95e51b5daa9..1637fb1af8e 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddTab.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/AddTab.jsx @@ -90,7 +90,7 @@ const AddTab = () => { return (
- + { tabs.map((tab) => ( diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/ClosableTab.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/ClosableTab.jsx index 84d8b1c3e36..bb780ff12fe 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/ClosableTab.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/ClosableTab.jsx @@ -75,7 +75,7 @@ const ClosableTab = () => { return (
- + { tabs.map((tab) => ( diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/IconOnlyTabs.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/IconOnlyTabs.jsx index 507cbf07b31..f4789366c7d 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/IconOnlyTabs.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/IconOnlyTabs.jsx @@ -37,7 +37,7 @@ const IconOnlyTabs = () => { return (
- + {searchTab} {briefcaseTab} {bookmarkTab} diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/IconsInMenuTabs.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/IconsInMenuTabs.jsx index 2a56c65d7e2..b1d559fab0f 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/IconsInMenuTabs.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/IconsInMenuTabs.jsx @@ -14,45 +14,45 @@ const cx = classNames.bind(styles); const IconsOnlyAndInMenuTabs = () => { const searchTab = ( - } showIcon key="Search"> - + } showIcon key="MenuTabSearch"> + ); const briefcaseTab = ( // eslint-disable-next-line react/forbid-component-props - } showIcon key="Briefcase"> - + } showIcon key="MenuTabBriefcase"> + ); const bookmarkTab = ( - } showIcon key="Bookmark"> - + } showIcon key="MenuTabBookmark"> + ); const calendarTab = ( - } showIcon key="Calendar"> - + } showIcon key="MenuTabCalendar"> + ); const envelopeTab = ( - } showIcon key="Envelope"> - + } showIcon key="MenuTabEnvelope"> + ); const printerTab = ( - } showIcon key="Printer"> - + } showIcon key="MenuTabPrinter"> + ); return (
- + {searchTab} {briefcaseTab} {bookmarkTab} diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabContentTemplate.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabContentTemplate.jsx index 40438c0d891..8f25e265be5 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabContentTemplate.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabContentTemplate.jsx @@ -9,10 +9,13 @@ const propTypes = { isLabelHidden: PropTypes.bool, label: PropTypes.string, children: PropTypes.node, + id: PropTypes.string, }; -const TabContentTemplate = ({ isLabelHidden, label, children }) => ( -
+const TabContentTemplate = ({ + isLabelHidden, label, id, children, +}) => ( +
{isLabelHidden ?

{label}

: null} {children || (
diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsTemplate.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsTemplate.jsx index 2681a3441bb..175049681c9 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsTemplate.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsTemplate.jsx @@ -2,7 +2,6 @@ import React from 'react'; import classNames from 'classnames/bind'; import PropTypes from 'prop-types'; import IconBriefcase from 'terra-icon/lib/icon/IconBriefcase'; -import IconSearch from 'terra-icon/lib/icon/IconSearch'; import Tabs from 'terra-tabs'; import TabContentTemplate from './TabContentTemplate'; import styles from './common/TabExample.module.scss'; @@ -14,59 +13,23 @@ const propTypes = { }; const TabsTemplate = (props) => { + const tabKey = props.id ? props.id : 'compact'; const labelTab = ( - - + + ); const iconTab = ( - } key="IconTab"> - + } key={`${tabKey}IconTab`} id={`${tabKey}IconTab`}> + ); - - const customTab = ( - - Custom display -
- )} - label="Custom display" - key="CustomTab" - > - - - ); - - const longLabel = ( - - - - ); - - const lastTab = ( - - - - ); - - const disabledTab = ( - } isDisabled key="DisabledTab" /> - ); return ( -
- +
+ {labelTab} {iconTab} - {customTab} - {disabledTab} - {longLabel} - {lastTab}
); diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsTemplateExpanded.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsTemplateExpanded.jsx index 3f290b3474a..92aee8c6d6e 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsTemplateExpanded.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsTemplateExpanded.jsx @@ -15,14 +15,14 @@ const propTypes = { const TabsTemplate = (props) => { const labelTab = ( - - + + ); const iconTab = ( - } key="IconTab"> - + } key="ExpandedIconTab"> + ); @@ -34,34 +34,34 @@ const TabsTemplate = (props) => {
)} label="Custom display" - key="CustomTab" + key="ExpandedCustomTab" > - +
); const longLabel = ( - + ); const lastTab = ( - - + + ); const disabledTab = ( - } isDisabled key="DisabledTab" /> + } isDisabled key="ExpandedDisabledTab" /> ); return (
- + {labelTab} {iconTab} {customTab} @@ -76,6 +76,6 @@ const TabsTemplate = (props) => { TabsTemplate.propTypes = propTypes; const TabExpanded = () => ( - + ); export default TabExpanded; diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsWithFilledContent.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsWithFilledContent.jsx index bd6810afcb8..4660a92e639 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsWithFilledContent.jsx +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/TabsWithFilledContent.jsx @@ -67,7 +67,7 @@ const TabsWithFilledContent = () => { return (
- + {tab1} {tab2} diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/VerticalTabs.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/VerticalTabs.jsx new file mode 100644 index 00000000000..adb6f4d5751 --- /dev/null +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/VerticalTabs.jsx @@ -0,0 +1,73 @@ +import React from 'react'; +import classNames from 'classnames/bind'; +import IconAdd from 'terra-icon/lib/icon/IconAdd'; +import IconPerson from 'terra-icon/lib/icon/IconPerson'; +import Tabs from 'terra-tabs'; +import TabContent from './TabContentTemplate'; +import styles from './common/TabExample.module.scss'; + +const cx = classNames.bind(styles); + +const VerticalTabs = () => { + const labelTab = ( + + + + ); + + const onlyiconTab = ( + } key="tonlyIconTab"> + + + ); + + const iconTab = ( + } key="tIconTab"> + + + ); + + const customTab = ( + + Surgical Department +
+ )} + label="Surgical Department" + key="tCustomTab" + > + + + ); + + const longLabel = ( + + + + ); + + const lastTab = ( + + + + ); + + return ( +
+ + {onlyiconTab} + {labelTab} + {iconTab} + {customTab} + {longLabel} + {lastTab} + +
+ ); +}; + +export default VerticalTabs; diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/common/TabExample.module.scss b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/common/TabExample.module.scss index 0d43cc3d800..8bccf7ca11a 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/common/TabExample.module.scss +++ b/packages/terra-framework-docs/src/terra-dev-site/doc/tabs/example/common/TabExample.module.scss @@ -18,4 +18,8 @@ height: 400px; padding: 25px; } + + .content-container-vertical { + height: 240px; + } } diff --git a/packages/terra-framework-docs/src/terra-dev-site/test/tabs/Tabs/TabsTemplate.module.scss b/packages/terra-framework-docs/src/terra-dev-site/test/tabs/Tabs/TabsTemplate.module.scss index 0c5aa97c9a5..290ecc9657e 100644 --- a/packages/terra-framework-docs/src/terra-dev-site/test/tabs/Tabs/TabsTemplate.module.scss +++ b/packages/terra-framework-docs/src/terra-dev-site/test/tabs/Tabs/TabsTemplate.module.scss @@ -16,4 +16,8 @@ height: 100%; padding: 20px; } + + .content-container-vertical { + height: 240px; + } } diff --git a/packages/terra-framework-docs/src/terra-dev-site/test/tabs/Tabs/VerticalTab.test.jsx b/packages/terra-framework-docs/src/terra-dev-site/test/tabs/Tabs/VerticalTab.test.jsx new file mode 100644 index 00000000000..197de855a78 --- /dev/null +++ b/packages/terra-framework-docs/src/terra-dev-site/test/tabs/Tabs/VerticalTab.test.jsx @@ -0,0 +1,74 @@ +import React from 'react'; +import classNames from 'classnames/bind'; +import IconBriefcase from 'terra-icon/lib/icon/IconBriefcase'; +import Tabs from 'terra-tabs'; +import TabContent from './TabContentTemplate'; +import styles from './TabsTemplate.module.scss'; + +const cx = classNames.bind(styles); + +const VerticalTab = () => { + const labelTab = ( + + + + ); + + const onlyiconTab = ( + } key="tonlyIconTab" id="tonlyIconTab"> + + + ); + + const iconTab = ( + } key="tIconTab" id="tIconTab"> + + + ); + + const customTab = ( + + Custom display +
+ )} + label="Custom display" + key="tCustomTab" + id="tCustomTab" + > + +
+ ); + + const longLabel = ( + + + + ); + + const lastTab = ( + + + + ); + + return ( +
+ + {onlyiconTab} + {labelTab} + {iconTab} + {customTab} + {longLabel} + {lastTab} + +
+ ); +}; + +export default VerticalTab; diff --git a/packages/terra-tabs/CHANGELOG.md b/packages/terra-tabs/CHANGELOG.md index da97634df99..18d94965718 100644 --- a/packages/terra-tabs/CHANGELOG.md +++ b/packages/terra-tabs/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Added + * Added Vertical orientation for `terra-tabs`. + * Changed * Removed additional screen reader phrase and fixed delete tab hint. diff --git a/packages/terra-tabs/src/StructuralTabs.module.scss b/packages/terra-tabs/src/StructuralTabs.module.scss index 7a9b846fbbf..c0114bfada9 100644 --- a/packages/terra-tabs/src/StructuralTabs.module.scss +++ b/packages/terra-tabs/src/StructuralTabs.module.scss @@ -8,6 +8,7 @@ :local { .structural { background-color: var(--terra-tabs-structural-container-background-color, #fff); + flex-direction: row; // Content div of content container component > :nth-child(2) { diff --git a/packages/terra-tabs/src/Tabs.jsx b/packages/terra-tabs/src/Tabs.jsx index bc71e280918..d671a470b95 100644 --- a/packages/terra-tabs/src/Tabs.jsx +++ b/packages/terra-tabs/src/Tabs.jsx @@ -79,6 +79,10 @@ const propTypes = { * The label to set on the add icon element. */ ariaLabelAddTab: PropTypes.string, + /** + * By Default Orientation will be Horizontal and Orientation will be Vertical When verticalOrientation set to `true`. + */ + verticalOrientation: PropTypes.bool, /** * Sets focus on content when set to `true`. */ @@ -91,6 +95,7 @@ const defaultProps = { isDraggable: false, isClosable: false, setFocusOnContent: false, + verticalOrientation: false, }; class Tabs extends React.Component { @@ -132,6 +137,7 @@ class Tabs extends React.Component { isDraggable, onTabOrderChange, isClosable, + verticalOrientation, setFocusOnContent, ...customProps } = this.props; @@ -158,6 +164,7 @@ class Tabs extends React.Component { } commonTabItems.push( {commonTabItems} diff --git a/packages/terra-tabs/src/clinical-lowlight-theme/Tabs.module.scss b/packages/terra-tabs/src/clinical-lowlight-theme/Tabs.module.scss index 24216646dae..f7ec56198ae 100644 --- a/packages/terra-tabs/src/clinical-lowlight-theme/Tabs.module.scss +++ b/packages/terra-tabs/src/clinical-lowlight-theme/Tabs.module.scss @@ -97,9 +97,20 @@ --terra-tabs-structural-transition-duration: 0; --terra-tabs-structural-transition-timing-function: ease; + --terra-tabs-structural-vertical-background-image: linear-gradient(to bottom, #141719, #141719); + --terra-tabs-structural-vertical-active-background-color: #222a2e; + --terra-tabs-structural-vertical-active-background-size: 100% 1px; + --terra-tabs-structural-vertical-active-box-shadow: none; + --terra-tabs-structural-vertical-active-color: #b2b5b6; + --terra-tabs-structural-vertical-active-font-weight: normal; + --terra-tabs-structural-vertical-background-size: 0 1px; + --terra-tabs-structural-vertical-border-width: 0 0 1px 0; + --terra-tabs-menu-icon-margin-right: 0.5rem; --terra-tabs-menu-icon-font-size: 1rem; + + /* NOTE: This is being commented out until discussions have been resolved around if modular tabs should be removed. --terra-tabs-modular-active-color: #000; diff --git a/packages/terra-tabs/src/common-tabs/CommonTabs.jsx b/packages/terra-tabs/src/common-tabs/CommonTabs.jsx index 7856687c7b2..25d5dee5b14 100644 --- a/packages/terra-tabs/src/common-tabs/CommonTabs.jsx +++ b/packages/terra-tabs/src/common-tabs/CommonTabs.jsx @@ -72,6 +72,10 @@ const propTypes = { * Callback function triggered when tab is drag and dropped . */ onTabOrderChange: PropTypes.func, + /** + * Whether tab is vertical or horizontal orientation. + */ + verticalOrientation: PropTypes.bool, }; const getTabId = (id, itemKey) => `${id || 'terra-common-tabs'}-${itemKey}`; @@ -91,6 +95,7 @@ const CommonTabs = ({ onClosingTab, isDraggable, onTabOrderChange, + verticalOrientation, ...customProps }) => { const theme = React.useContext(ThemeContext); @@ -120,6 +125,12 @@ const CommonTabs = ({ theme.className, ), customProps.className); + const contentTabClassNames = classNames(cx( + 'body', + { 'is-vertical': verticalOrientation }, + { 'body-padding': variant === 'workspace' }, + theme.className, + )); const handleCommonTabsStateChange = (value, itemKey, event) => { onClosingTab(value, itemKey, event); @@ -134,9 +145,9 @@ const CommonTabs = ({
- +
-
+
{React.Children.map(children, child => { let portalElement = commonTabsPortalsRef.current[child.props.itemKey]?.element; if (!portalElement) { diff --git a/packages/terra-tabs/src/common-tabs/CommonTabs.module.scss b/packages/terra-tabs/src/common-tabs/CommonTabs.module.scss index 49f069e329d..881c5688186 100644 --- a/packages/terra-tabs/src/common-tabs/CommonTabs.module.scss +++ b/packages/terra-tabs/src/common-tabs/CommonTabs.module.scss @@ -51,6 +51,7 @@ .body { border-bottom-left-radius: var(--terra-tabs-workspace-body-border-bottom-left-radius, 3px); border-bottom-right-radius: var(--terra-tabs-workspace-body-border-bottom-right-radius, 3px); + border-left: 0; border-top: 1px solid #868a8c; flex: 1 1 auto; height: 100%; @@ -59,8 +60,15 @@ } .body-padding { + flex-direction: column; padding-left: 10px; padding-right: 10px; + z-index: 10; + } + + .is-vertical { + border-left: 1px solid #868a8c; + border-top: 0; } .is-overlay .body { diff --git a/packages/terra-tabs/src/common-tabs/Tab.module.scss b/packages/terra-tabs/src/common-tabs/Tab.module.scss index 10f076c6f01..ddf2f16f2b0 100644 --- a/packages/terra-tabs/src/common-tabs/Tab.module.scss +++ b/packages/terra-tabs/src/common-tabs/Tab.module.scss @@ -103,6 +103,26 @@ } } + + &.is-active-vertical { + background-color: var(--terra-tabs-workspace-tab-is-active-background-color, #fff); + background-image: var(--terra-tabs-workspace-tab-is-active-background-image, none); + height: var(--terra-tabs-workspace-tab-is-active-height, 34px); + + .icon, + .label { + margin-top: var(--terra-tabs-workspace-tab-is-active-icon-label-margin-top, -1px); + } + + .icon { + color: var(--terra-tabs-workspace-tab-is-active-icon-color, #64696c); + } + + .label { + color: var(--terra-tabs-workspace-tab-is-active-label-color, #434a4d); + } + } + &.is-disabled { background-color: var(--terra-tabs-structural-disabled-background-color, #fff); background-size: 0 0; diff --git a/packages/terra-tabs/src/common-tabs/TerraStructuralTabs.module.scss b/packages/terra-tabs/src/common-tabs/TerraStructuralTabs.module.scss index df73757ad63..93fef6d6f5c 100644 --- a/packages/terra-tabs/src/common-tabs/TerraStructuralTabs.module.scss +++ b/packages/terra-tabs/src/common-tabs/TerraStructuralTabs.module.scss @@ -111,6 +111,49 @@ transition-property: background-size; transition-timing-function: var(--terra-tabs-structural-transition-timing-function, ease); + &.is-vertical { + background-image: var(--terra-tabs-structural-vertical-background-image, linear-gradient(to bottom, #dedfe0, #dedfe0)); + background-size: var(--terra-tabs-structural-vertical-background-size, 0 1px); + border-width: var(--terra-tabs-structural-vertical-border-width, 0 0 1px 0); + min-width: 2.571rem; + } + + + &.is-active-vertical { + background-color: var(--terra-tabs-structural-vertical-active-background-color, #fff); + background-size: var(--terra-tabs-structural-vertical-active-background-size, 100% 1px); + border-bottom: 1px solid; + border-image: linear-gradient(#006fc3, #006fc3) 0 100%; + border-left: 2px solid; + border-width: 0 0 1px 2px; + box-shadow: var(--terra-tabs-structural-vertical-active-box-shadow, none); + color: var(--terra-tabs-structural-vertical-active-color, #000); + font-weight: var(--terra-tabs-structural-vertical-active-font-weight, normal); + outline: none; + overflow: hidden; //forces :before background-image to honor border-radius clipping. + position: relative; + z-index: var(--terra-tabs-structural-vertical-active-z-index); + + &::before { + background-clip: content-box; // Make sure background fully extends + transition-duration: var(--terra-tabs-structural-active-before-transition-duration, 0); + transition-property: width; + transition-timing-function: var(--terra-tabs-structural-active-before-transition-timing-function, ease); + width: 100%; + } + + // Same as the selectors below, but due to the specificity, you can override the variables + // scoped specifically to the active tab + @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none), (hover: hover) and (pointer: fine) { + &:hover { + background-color: var(--terra-tabs-structural-active-hover-background-color, #fff); + background-image: var(--terra-tabs-structural-active-hover-background-image, linear-gradient(to bottom, #dedfe0, #dedfe0)); + background-size: var(--terra-tabs-structural-active-hover-background-size, 100% 2px); + color: var(--terra-tabs-structural-active-hover-color, #000); + } + } + } + &.is-active { background-color: var(--terra-tabs-structural-active-background-color, #fff); background-image: var(--terra-tabs-structural-active-background-image, linear-gradient(to bottom, #006fc3, #006fc3)); diff --git a/packages/terra-tabs/src/common-tabs/TerraTabs.module.scss b/packages/terra-tabs/src/common-tabs/TerraTabs.module.scss index f2b0fa3cdb4..03714ff86e1 100644 --- a/packages/terra-tabs/src/common-tabs/TerraTabs.module.scss +++ b/packages/terra-tabs/src/common-tabs/TerraTabs.module.scss @@ -59,6 +59,7 @@ flex: 0 1 auto; min-width: 8.357rem; text-align: center; + @media (max-width: 768px) { min-width: 5rem; /* Reduce the minimum width of the tabs */ padding: 0.643rem 0.5rem; /* Adjust padding for smaller screens */ @@ -74,6 +75,10 @@ flex: 0 0 auto; min-width: 2.571rem; padding: 0.643rem 1.071rem; + + .is-vertical { + padding: 0; + } } &.is-text-only { diff --git a/packages/terra-tabs/src/common-tabs/_AddButton.jsx b/packages/terra-tabs/src/common-tabs/_AddButton.jsx index 3f41a807622..7339ff30b36 100644 --- a/packages/terra-tabs/src/common-tabs/_AddButton.jsx +++ b/packages/terra-tabs/src/common-tabs/_AddButton.jsx @@ -77,7 +77,7 @@ const AddButton = ({ icon={AddTabIcon} isIconOnly id={id} - tabindex="-1" + tabIndex="-1" index={index} text={addAriaLabel} variant="de-emphasis" diff --git a/packages/terra-tabs/src/common-tabs/_Tab.jsx b/packages/terra-tabs/src/common-tabs/_Tab.jsx index 3cce6228632..8de966b75f4 100644 --- a/packages/terra-tabs/src/common-tabs/_Tab.jsx +++ b/packages/terra-tabs/src/common-tabs/_Tab.jsx @@ -118,6 +118,10 @@ const propTypes = { * Parameters: 1. label of the closing tab 2. Selected pane's key 3. Event */ onClosingTab: PropTypes.func, + /** + * By Default Orientation will be Horizontal and Orientation will be Vertical When verticalOrientation prop is passed. + */ + verticalOrientation: PropTypes.bool, }; const defaultProps = { @@ -126,6 +130,7 @@ const defaultProps = { isDisabled: false, showIcon: false, isDraggable: false, + verticalOrientation: false, }; const Tab = ({ @@ -149,16 +154,18 @@ const Tab = ({ onClosingTab, intl, isDraggable, + verticalOrientation, }) => { const tabDeleteLabel = intl.formatMessage({ id: 'Terra.tabs.hint.removable' }); const attributes = {}; const theme = React.useContext(ThemeContext); const tabClassNames = cx( 'tab', - { 'is-active': isSelected }, + { 'is-active': !verticalOrientation && isSelected }, { 'is-icon-only': isIconOnly }, { 'is-text-only': !icon }, { 'is-disabled': isDisabled }, + { 'is-active-vertical': verticalOrientation && isSelected }, theme.className, ); const paneClassNames = classNames(cy( @@ -166,7 +173,9 @@ const Tab = ({ { 'is-disabled': isDisabled }, { 'is-icon-only': isIconOnly }, { 'is-text-only': !icon }, - { 'is-active': isSelected }, + { 'is-active': !verticalOrientation && isSelected }, + { 'is-active-vertical': verticalOrientation && isSelected }, + { 'is-vertical': verticalOrientation }, theme.className, )); diff --git a/packages/terra-tabs/src/common-tabs/_Tabs.jsx b/packages/terra-tabs/src/common-tabs/_Tabs.jsx index 2bfd6a8589a..e615eef883c 100644 --- a/packages/terra-tabs/src/common-tabs/_Tabs.jsx +++ b/packages/terra-tabs/src/common-tabs/_Tabs.jsx @@ -22,7 +22,7 @@ const propTypes = { /** * The label to set on the tablist element. */ - ariaLabel: PropTypes.string.isRequired, + ariaLabel: PropTypes.string, /** * The label to set on the add icon element. */ @@ -101,6 +101,10 @@ const propTypes = { * intl object programmatically imported through injectIntl from react-intl. */ intl: PropTypes.shape({ formatMessage: PropTypes.func }).isRequired, + /** + * By Default Orientation will be Horizontal and Orientation will be Vertical When verticalOrientation prop is passed. + */ + verticalOrientation: PropTypes.bool, }; class Tabs extends React.Component { @@ -251,7 +255,7 @@ class Tabs extends React.Component { const tabMinWidth = parseFloat(tabStyle.getPropertyValue('min-width')); calcMinWidth += (tabMinWidth + tabMarginLeft + tabMarginRight); - if (calcMinWidth > availableWidth && !(i === tabCount - 1 && calcMinWidth <= width)) { + if (calcMinWidth > availableWidth && !(i === tabCount - 1 && calcMinWidth <= width) && !this.props.verticalOrientation) { newHideIndex = i; showMoreButton = true; break; @@ -470,7 +474,7 @@ class Tabs extends React.Component { render() { const { - ariaLabel, variant, onChange, onSelectAddButton, ariaLabelAddTab, isDraggable, + ariaLabel, variant, onChange, onSelectAddButton, ariaLabelAddTab, isDraggable, verticalOrientation, } = this.props; const theme = this.context; const enabledTabs = this.state.visibleTabData.filter(tab => !tab.isDisabled); @@ -506,6 +510,7 @@ class Tabs extends React.Component { showIcon={tab.showIcon} onClosingTab={this.wrapOnClose()} isDraggable={isDraggable} + verticalOrientation={verticalOrientation} />, ); } else { @@ -563,8 +568,8 @@ class Tabs extends React.Component { 'data-tab-is-calculating': 'true', }; } - const commonTabsClassNames = cx('tab-container', theme.className); - const commonTabsContainerClassNames = cx('container', theme.className); + const commonTabsClassNames = verticalOrientation ? cx('tab-container-vertical', theme.className) : cx('tab-container', theme.className); + const commonTabsContainerClassNames = verticalOrientation ? cx('container-vertical', theme.className) : cx('container', theme.className); const commonDivClassNames = cx('divcontainer', theme.className); window['__react-beautiful-dnd-disable-dev-warnings'] = true; @@ -572,7 +577,7 @@ class Tabs extends React.Component { if (isDraggable) { return ( - + {(provided) => (
@@ -644,7 +649,7 @@ class Tabs extends React.Component { className={commonTabsClassNames} role="tablist" aria-label={ariaLabel} - aria-orientation="horizontal" + aria-orientation={verticalOrientation ? 'vertical' : 'horizontal'} aria-owns={hiddenIds.join(' ')} > {visibleTabs} diff --git a/packages/terra-tabs/src/common-tabs/_Tabs.module.scss b/packages/terra-tabs/src/common-tabs/_Tabs.module.scss index e612ae2facf..cc2db32633c 100644 --- a/packages/terra-tabs/src/common-tabs/_Tabs.module.scss +++ b/packages/terra-tabs/src/common-tabs/_Tabs.module.scss @@ -23,11 +23,40 @@ } } + .tab-container-vertical { + display: flex; + flex: 1 1 auto; + flex-direction: column; + flex-wrap: nowrap; + float: left; + height: fit-content; + justify-content: flex-start; + margin-bottom: var(--terra-tabs-workspace-tab-container-margin-bottom, 0); + max-width: 25%; + padding: 0; + position: relative; + width: fit-content; + + &:focus { + outline: none; + } + + &[data-tab-is-calculating='true'] { + visibility: hidden; + } + } + .container { // while using the Flex the style of addIcon getting align to all right to the tabs display: -webkit-box; // stylelint-disable value-no-vendor-prefix } + .container-vertical { + flex: 1 1 auto; + flex-flow: row nowrap; + flex-direction: row; + } + .divcontainer { max-width: 40px; } diff --git a/packages/terra-tabs/src/orion-fusion-theme/Tabs.module.scss b/packages/terra-tabs/src/orion-fusion-theme/Tabs.module.scss index a7a3d66658f..a43858767f1 100644 --- a/packages/terra-tabs/src/orion-fusion-theme/Tabs.module.scss +++ b/packages/terra-tabs/src/orion-fusion-theme/Tabs.module.scss @@ -10,7 +10,7 @@ --terra-tabs-line-height: 1.41666667rem; --terra-tabs-padding: 0.5rem 1.25rem; --terra-tabs-text-only-padding: 0.5rem 1.25rem; - --terra-tabs-text-only-draggable-padding: 0.5rem 0.25rem; + --terra-tabs-text-only-draggable-padding: 0.9rem 0.25rem; --terra-tabs-label-next-to-icon-margin-left: 0.25rem; --terra-tabs-menu-arrow-margin-left: 0.5rem; --terra-tabs-menu-collapsed-justify-content: center; @@ -96,6 +96,15 @@ --terra-tabs-structural-collapsed-menu-bar-focus-border-bottom-color: none; --terra-tabs-structural-collapsed-menu-bar-focus-border-bottom-width: 0; + --terra-tabs-structural-vertical-background-image: linear-gradient(to bottom, #dedfe0, #dedfe0); + --terra-tabs-structural-vertical-active-background-color: #fff; + --terra-tabs-structural-vertical-active-background-size: 100% 1px; + --terra-tabs-structural-vertical-active-box-shadow: none; + --terra-tabs-structural-vertical-active-color: #000; + --terra-tabs-structural-vertical-active-font-weight: normal; + --terra-tabs-structural-vertical-background-size: 0 1px; + --terra-tabs-structural-vertical-border-width: 0 0 1px 0; + --terra-tabs-menu-icon-margin-right: 0.25rem; --terra-tabs-menu-icon-font-size: 1rem; diff --git a/packages/terra-tabs/tests/jest/Tabs.test.jsx b/packages/terra-tabs/tests/jest/Tabs.test.jsx index 4a1d9361e68..7665fc49355 100644 --- a/packages/terra-tabs/tests/jest/Tabs.test.jsx +++ b/packages/terra-tabs/tests/jest/Tabs.test.jsx @@ -117,4 +117,16 @@ describe('Tabs', () => { ); expect(defaultRender).toMatchSnapshot(); }); + + it('should render vertical tab', () => { + const defaultRender = ; + const wrapper = shallowWithIntl(defaultRender).dive(); + expect(wrapper).toMatchSnapshot(); + }); + + it('should render horizontal tab if verticalorientation is passed as null', () => { + const defaultRender = ; + const wrapper = shallowWithIntl(defaultRender).dive(); + expect(wrapper).toMatchSnapshot(); + }); }); diff --git a/packages/terra-tabs/tests/jest/__snapshots__/Tabs.test.jsx.snap b/packages/terra-tabs/tests/jest/__snapshots__/Tabs.test.jsx.snap index 478fde800a8..35d53ee1b99 100644 --- a/packages/terra-tabs/tests/jest/__snapshots__/Tabs.test.jsx.snap +++ b/packages/terra-tabs/tests/jest/__snapshots__/Tabs.test.jsx.snap @@ -42,6 +42,7 @@ exports[`Tabs correctly applies the theme context className 1`] = ` setFocusOnContent={false} tabFill={false} variant="modular-left-aligned" + verticalOrientation={false} >
+
+
+`; + +exports[`Tabs should render horizontal tab if verticalorientation is passed as null 1`] = ` +
+
+
+
+
+ +
+
+ +
+
+`; + +exports[`Tabs should render vertical tab 1`] = ` +
+
+
+
+
+ +
+
+
@@ -1852,7 +2001,7 @@ exports[`Tabs should render with add icon 1`] = ` isDisabled={false} isIconOnly={false} itemKey="default" - key="default/.0" + key=".$default" label="Default" portalElement={null} render={[Function]} @@ -1945,6 +2094,7 @@ exports[`Tabs should render with add icon 2`] = ` onSelectAddButton={[Function]} setFocusOnContent={false} tabFill={false} + verticalOrientation={false} >
@@ -2469,7 +2624,7 @@ exports[`Tabs should render with add icon 2`] = ` isDisabled={false} isIconOnly={false} itemKey="default" - key="default/.0" + key=".$default" label="Default" portalElement={null} render={[Function]} @@ -2562,6 +2717,7 @@ exports[`Tabs should render with close icon 1`] = ` onTabClose={[MockFunction]} setFocusOnContent={false} tabFill={false} + verticalOrientation={false} >
diff --git a/packages/terra-tabs/tests/wdio/__snapshots__/reference/clinical-lowlight-theme/en/chrome_medium/tabs-spec/Keyboard_Focus_on_First_Tab.png b/packages/terra-tabs/tests/wdio/__snapshots__/reference/clinical-lowlight-theme/en/chrome_medium/tabs-spec/Keyboard_Focus_on_First_Tab.png new file mode 100644 index 00000000000..368b063f64b Binary files /dev/null and b/packages/terra-tabs/tests/wdio/__snapshots__/reference/clinical-lowlight-theme/en/chrome_medium/tabs-spec/Keyboard_Focus_on_First_Tab.png differ diff --git a/packages/terra-tabs/tests/wdio/__snapshots__/reference/orion-fusion-theme/en/chrome_medium/tabs-spec/Keyboard_Focus_on_First_Tab.png b/packages/terra-tabs/tests/wdio/__snapshots__/reference/orion-fusion-theme/en/chrome_medium/tabs-spec/Keyboard_Focus_on_First_Tab.png new file mode 100644 index 00000000000..e87764e64b9 Binary files /dev/null and b/packages/terra-tabs/tests/wdio/__snapshots__/reference/orion-fusion-theme/en/chrome_medium/tabs-spec/Keyboard_Focus_on_First_Tab.png differ diff --git a/packages/terra-tabs/tests/wdio/__snapshots__/reference/terra-default-theme/en/chrome_medium/tabs-spec/Keyboard_Focus_on_First_Tab.png b/packages/terra-tabs/tests/wdio/__snapshots__/reference/terra-default-theme/en/chrome_medium/tabs-spec/Keyboard_Focus_on_First_Tab.png new file mode 100644 index 00000000000..0a8fd5eb69d Binary files /dev/null and b/packages/terra-tabs/tests/wdio/__snapshots__/reference/terra-default-theme/en/chrome_medium/tabs-spec/Keyboard_Focus_on_First_Tab.png differ diff --git a/packages/terra-tabs/tests/wdio/tabs-spec.js b/packages/terra-tabs/tests/wdio/tabs-spec.js index d77b2d21ae7..12a597563fd 100644 --- a/packages/terra-tabs/tests/wdio/tabs-spec.js +++ b/packages/terra-tabs/tests/wdio/tabs-spec.js @@ -219,3 +219,12 @@ Terra.describeViewports('Tabs - Keyboard Focus with interactive element', ['medi Terra.validates.element('Keyboard Focus on First Interactive Element', { selector: '#root' }); }); }); + +Terra.describeViewports('Tabs - Vertical Tabs', ['medium'], () => { + it('displays vertical tab', () => { + browser.url('/raw/tests/cerner-terra-framework-docs/tabs/tabs/vertical-tab'); + browser.keys('Tab'); + browser.keys('Tab'); + Terra.validates.element('Keyboard Focus on First Tab', { selector: '#root' }); + }); +});