Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tabs): add headerWidth prop (FE-4161) #4202

Merged
merged 3 commits into from
Jul 6, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const StyledTabsHeaderWrapper = styled.div`
css`
overflow-y: auto;
padding: 2px;
box-sizing: border-box;

${!isInSidebar &&
css`
Expand Down
14 changes: 14 additions & 0 deletions src/components/tabs/tabs.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const Tabs = ({
borders = "off",
variant = "default",
validationStatusOverride,
headerWidth,
...rest
}) => {
const tabRefs = useRef([]);
Expand Down Expand Up @@ -319,6 +320,7 @@ const Tabs = ({
{...tagComponent("tabs", rest)}
isInSidebar={isInSidebar}
mt={position === "left" || isInSidebar ? "0px" : "15px"}
headerWidth={headerWidth}
{...rest}
>
{renderTabHeaders()}
Expand Down Expand Up @@ -356,6 +358,18 @@ Tabs.propTypes = {
"no right side",
"no sides",
]),
/** sets width to the tab headers. Can be any valid CSS string.
* The headerWidth prop works only for `position="left"`
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it worth maybe having a custom prop validation here now that this prop works only when the position="left"

*/
headerWidth: (props, propName, componentName) => {
if (props.position !== "left" && props[propName] !== undefined) {
return new Error(
`Invalid usage of prop ${propName} in ${componentName}. The ${propName} can be used only if position is set to left`
);
}

return null;
},
/** Adds an alternate styling variant to the tab titles. */
variant: PropTypes.oneOf(["default", "alternate"]),
/** An object to support overriding validation statuses, when the Tabs have custom targets for example.
Expand Down
4 changes: 4 additions & 0 deletions src/components/tabs/tabs.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export interface TabsProps extends MarginProps {
borders?: "off" | "on" | "no left side" | "no right side" | "no sides";
/** Adds an alternate styling variant to the tab titles. */
variant?: "default" | "alternate";
/** sets width to the tab headers. Can be any valid CSS string.
* The headerWidth prop works only for `position="left"`
*/
headerWidth?: string;
/** An object to support overriding validation statuses, when the Tabs have custom targets for example.
* The `id` property should match the `tabId`s for the rendered Tabs.
*/
Expand Down
63 changes: 63 additions & 0 deletions src/components/tabs/tabs.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@
import React, { useEffect, useContext } from "react";
import { mount, shallow } from "enzyme";
import { act } from "react-dom/test-utils";
import { css } from "styled-components";
import TabTitle from "./__internal__/tab-title/tab-title.component";
import { Tabs, Tab } from "./tabs.component";
import { TabContext } from "./tab/index";
import { rootTagTest } from "../../utils/helpers/tags/tags-specs/tags-specs";
import StyledTabs from "./tabs.style";
import StyledTab from "./tab/tab.style";
import {
assertStyleMatch,
simulate,
testStyledSystemMargin,
} from "../../__spec_helper__/test-utils";
import { StyledTabsHeaderWrapper } from "./__internal__/tabs-header/tabs-header.style";
import { SidebarContext } from "../drawer";

function render(props) {
Expand Down Expand Up @@ -155,6 +158,66 @@ describe("Tabs", () => {
{ mt: "0px" }
);

describe("when `headerWidth` is provided", () => {
describe.each(["35%", "100px", "5em"])(
"and value of %s is provided",
(headerWidth) => {
it("should render correct `width` in `TabsHeader` component, and `Tab` `width` should be `auto`", () => {
const wrapper = mount(
<Tabs position="left" headerWidth={headerWidth}>
<Tab title="Tab Title 1" tabId="uniqueid1">
TabContent
</Tab>
</Tabs>
);

assertStyleMatch(
{
width: headerWidth,
},
wrapper,
{
modifier: css`
${StyledTabsHeaderWrapper}
`,
}
);

assertStyleMatch(
{
width: "auto",
},
wrapper,
{
modifier: css`
${StyledTab}
`,
}
);
});
}
);
});

describe('when `headerWidth` is provided, and `position="top"`', () => {
it(" should render console error", () => {
jest.spyOn(global.console, "error").mockImplementation(() => {});

mount(
<Tabs position="top" headerWidth="500px">
<Tab title="Tab Title 1" tabId="uniqueid1">
TabContent
</Tab>
</Tabs>
);

// eslint-disable-next-line no-console
expect(console.error).toHaveBeenCalledWith(
"Warning: Failed prop type: Invalid usage of prop headerWidth in Tabs. The headerWidth can be used only if position is set to left\n in Tabs"
);
});
});

describe("when passing custom className as a prop", () => {
it("adds it to the classList", () => {
const wrapper = render({ className: "class" });
Expand Down
3 changes: 2 additions & 1 deletion src/components/tabs/tabs.stories.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { select, withKnobs } from "@storybook/addon-knobs";
import { select, withKnobs, text } from "@storybook/addon-knobs";
import { Tabs, Tab } from "./tabs.component";

export default {
Expand All @@ -19,6 +19,7 @@ export default {
export const Default = () => {
return (
<Tabs
headerWidth={text("headerWidth", "")}
align={select("align", ["left", "right"], "left")}
position={select("position", ["top", "left"], "top")}
borders={select(
Expand Down
58 changes: 58 additions & 0 deletions src/components/tabs/tabs.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1520,6 +1520,64 @@ By setting the `variant` prop to "alternate" it is possible to apply some additi
</Story>
</Preview>

### With headerWidth
The `headerWidth` prop works only if prop `position` is set to `left`.

<Preview>
<Story name="with headerWidth">
{() => {
return (
<div style={{ padding: "4px" }}>
<Tabs headerWidth="400px" align="left" position="left">
<Tab
errorMessage="error"
warningMessage="warning"
infoMessage="info"
tabId="tab-1"
title="Very long title for Tab 1 without with prop it would be not well aligned with the second Tabs group"
key="tab-1"
>
Content for tab 1
</Tab>
<Tab
errorMessage="error"
warningMessage="warning"
infoMessage="info"
tabId="tab-2"
title="Tab 2"
key="tab-2"
>
Content for tab 2
</Tab>
</Tabs>
<Tabs headerWidth="400px" align="left" position="left">
<Tab
errorMessage="error"
warningMessage="warning"
infoMessage="info"
tabId="tab-1"
title="Tab 1"
key="tab-1"
>
Content for tab 1
</Tab>
<Tab
errorMessage="error"
warningMessage="warning"
infoMessage="info"
tabId="tab-2"
title="Tab 2"
key="tab-2"
>
Content for tab 2
</Tab>
</Tabs>
</div>
);
}}
</Story>
</Preview>

### With custom spacing
The `Tabs`component also allows you to pass custom margin spacing, whilst `Tab` components support custom padding spacings.
The spacing modifiers support being passed either a number between 1 and 8 that is then multiplied by `8px` or any valid
Expand Down
15 changes: 14 additions & 1 deletion src/components/tabs/tabs.style.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,26 @@ import styled, { css } from "styled-components";
import { margin } from "styled-system";
import PropTypes from "prop-types";
import BaseTheme from "../../style/themes/base";
import { StyledTabsHeaderWrapper } from "./__internal__/tabs-header/tabs-header.style";
import StyledTab from "./tab/tab.style";

const StyledTabs = styled.div`
${({ position, inSidebar, theme }) => css`
${({ position, inSidebar, theme, headerWidth }) => css`
color: ${theme.text.color};

${position === "left" &&
css`
${headerWidth &&
css`
${StyledTabsHeaderWrapper} {
width: ${headerWidth};
}

${StyledTab} {
width: auto;
}
`}

${!inSidebar &&
css`
display: flex;
Expand Down