diff --git a/src/__internal__/input/__snapshots__/input-presentation.spec.tsx.snap b/src/__internal__/input/__snapshots__/input-presentation.spec.tsx.snap index 6956748525..c9886f80c6 100644 --- a/src/__internal__/input/__snapshots__/input-presentation.spec.tsx.snap +++ b/src/__internal__/input/__snapshots__/input-presentation.spec.tsx.snap @@ -10,6 +10,7 @@ exports[`InputPresentation renders presentational div and context provider for i display: -ms-flexbox; display: flex; position: relative; + max-width: 100%; } .c1 { diff --git a/src/__internal__/input/input-presentation.component.tsx b/src/__internal__/input/input-presentation.component.tsx index b768411794..6fa741faa9 100644 --- a/src/__internal__/input/input-presentation.component.tsx +++ b/src/__internal__/input/input-presentation.component.tsx @@ -16,6 +16,11 @@ export interface CommonInputPresentationProps extends ValidationProps { align?: string; /** The width of the input as a percentage */ inputWidth?: number; + /** + * Prop for specifying the max width of the input. + * Leaving the `maxWidth` prop with no value will default the width to '100%' + */ + maxWidth?: string; /** If true, the component will be read-only */ readOnly?: boolean; /** Size of an input */ @@ -33,6 +38,7 @@ const InputPresentation = ({ children, positionedChildren, inputWidth, + maxWidth, align, disabled, readOnly, @@ -63,7 +69,10 @@ const InputPresentation = ({ }; return ( - + {positionedChildren} { }); }); + describe("maxWidth", () => { + it("renders correctly with a custom maxWidth", () => { + assertStyleMatch( + { + maxWidth: "54%", + }, + render({ maxWidth: "54%", children: "Children" }) + ); + }); + + it("renders correctly as 100% as maxWidth has been left with no value", () => { + assertStyleMatch( + { + maxWidth: "100%", + }, + render({ maxWidth: "", children: "Children" }) + ); + }); + }); + describe.each([ ["error", "var(--colorsSemanticNegative500)"], ["warning", "var(--colorsSemanticCaution500)"], diff --git a/src/__internal__/input/input-presentation.style.ts b/src/__internal__/input/input-presentation.style.ts index 377aecdaeb..7685dfe98b 100644 --- a/src/__internal__/input/input-presentation.style.ts +++ b/src/__internal__/input/input-presentation.style.ts @@ -6,11 +6,12 @@ import { InputContextProps } from "../input-behaviour"; import { CarbonProviderProps } from "../../components/carbon-provider"; export const StyledInputPresentationContainer = styled.div< - Pick + Pick >` flex: 0 0 ${({ inputWidth }) => inputWidth}%; display: flex; position: relative; + max-width: ${({ maxWidth }) => (maxWidth ? `${maxWidth}` : "100%")}; `; function stylingForValidations({ diff --git a/src/components/date/date.component.js b/src/components/date/date.component.js index a925cdaeea..17d095fb80 100644 --- a/src/components/date/date.component.js +++ b/src/components/date/date.component.js @@ -371,6 +371,7 @@ const DateInput = ({ DateInput.propTypes = { ...Textbox.propTypes, + maxWidth: undefined, ...marginPropTypes, /** Pass any props that match the [DayPickerProps](https://react-day-picker-v7.netlify.app/docs/getting-started/) * interface to override default behaviors diff --git a/src/components/date/date.stories.mdx b/src/components/date/date.stories.mdx index 39527f7301..f7376b6434 100644 --- a/src/components/date/date.stories.mdx +++ b/src/components/date/date.stories.mdx @@ -631,6 +631,7 @@ Due to the `Textbox` component being used internally by the `Date` component the { expect(label.prop("isRequired")).toBe(true); }); }); + + describe("when maxWidth is passed", () => { + it("should be passed to InputPresentation", () => { + mount(); + + assertStyleMatch( + { + maxWidth: "67%", + }, + wrapper.find(InputPresentation) + ); + }); + + it("renders correctly as 100% as maxWidth has been left with no value", () => { + mount(); + assertStyleMatch( + { + maxWidth: "100%", + }, + wrapper.find(InputPresentation) + ); + }); + }); }); diff --git a/src/components/decimal/decimal.stories.mdx b/src/components/decimal/decimal.stories.mdx index 9a9839aaef..a700129394 100644 --- a/src/components/decimal/decimal.stories.mdx +++ b/src/components/decimal/decimal.stories.mdx @@ -93,6 +93,15 @@ import Decimal from "carbon-react/lib/components/decimal"; /> +### With custom maxWidth + + + + + ### With fieldHelp diff --git a/src/components/decimal/decimal.stories.tsx b/src/components/decimal/decimal.stories.tsx index 612fa848ca..9d0c8812bb 100644 --- a/src/components/decimal/decimal.stories.tsx +++ b/src/components/decimal/decimal.stories.tsx @@ -91,6 +91,11 @@ WithCustomLabelWidthAndInputWidth.args = { labelInline: true, }; +export const WithCustomMaxWidth = DefaultStory.bind({}); +WithCustomMaxWidth.args = { + maxWidth: "50%", +}; + export const WithFieldHelp = DefaultStory.bind({}); WithFieldHelp.args = { fieldHelp: "Help" }; diff --git a/src/components/decimal/decimal.test.js b/src/components/decimal/decimal.test.js index ae7116aae8..2f3a7aadbe 100644 --- a/src/components/decimal/decimal.test.js +++ b/src/components/decimal/decimal.test.js @@ -257,6 +257,33 @@ context("Tests for Decimal component", () => { }); }); + it.each([ + ["10%", "10%"], + ["30%", "30%"], + ["50%", "50%"], + ["80%", "80%"], + ["100%", "100%"], + ])( + "should use %s as maxWidth and render it with correct corresponding max-width percentage", + (input, totalWidth) => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", totalWidth); + } + ); + + it("as maxWidth has no value it should render as 100%", () => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", "100%"); + }); + it("can have a custom onChange handler", () => { const CustomDecimalComponent = ({ onChange, value, ...props }) => { const [state, setState] = React.useState("0.01"); diff --git a/src/components/grouped-character/grouped-character.spec.tsx b/src/components/grouped-character/grouped-character.spec.tsx index 15d5f6ee13..186b284728 100644 --- a/src/components/grouped-character/grouped-character.spec.tsx +++ b/src/components/grouped-character/grouped-character.spec.tsx @@ -1,16 +1,29 @@ import React from "react"; import { HTMLAttributes, mount, ReactWrapper } from "enzyme"; -import { testStyledSystemMargin } from "../../__spec_helper__/test-utils"; import GroupedCharacter, { GroupedCharacterProps, } from "./grouped-character.component"; +import { + assertStyleMatch, + testStyledSystemMargin, +} from "../../__spec_helper__/test-utils"; import FormFieldStyle from "../../__internal__/form-field/form-field.style"; import Label from "../../__internal__/label"; +import { InputPresentation } from "../../__internal__/input"; const mountComponent = (props: GroupedCharacterProps) => mount(); +function renderGroupedCharacter( + props: Partial, + renderer = mount +) { + return renderer( + + ); +} + describe("GroupedCharacter", () => { jest.useFakeTimers(); const basicGroupConfig = [2, 2, 4]; @@ -245,4 +258,28 @@ describe("GroupedCharacter", () => { expect(label.prop("isRequired")).toBe(true); }); }); + + describe("when maxWidth is passed", () => { + it("should be passed to InputPresentation", () => { + const wrapper = renderGroupedCharacter({ maxWidth: "67%" }); + + assertStyleMatch( + { + maxWidth: "67%", + }, + wrapper.find(InputPresentation) + ); + }); + + it("renders correctly as 100% as maxWidth has been left with no value", () => { + const wrapper = renderGroupedCharacter({ maxWidth: "" }); + + assertStyleMatch( + { + maxWidth: "100%", + }, + wrapper.find(InputPresentation) + ); + }); + }); }); diff --git a/src/components/grouped-character/grouped-character.stories.mdx b/src/components/grouped-character/grouped-character.stories.mdx index 0d1e8e62f4..bc16847f93 100644 --- a/src/components/grouped-character/grouped-character.stories.mdx +++ b/src/components/grouped-character/grouped-character.stories.mdx @@ -84,6 +84,30 @@ import GroupedCharacter from "carbon-react/lib/components/grouped-character"; /> +### With custom maxWidth + + + + {() => { + const [state, setState] = useState("1231231"); + const setValue = ({ target }) => { + setState(target.value.rawValue); + }; + return ( + + ); + }} + + + + ### With fieldHelp diff --git a/src/components/grouped-character/grouped-character.test.js b/src/components/grouped-character/grouped-character.test.js index 8b0e8a765a..ea27d0c754 100644 --- a/src/components/grouped-character/grouped-character.test.js +++ b/src/components/grouped-character/grouped-character.test.js @@ -181,6 +181,33 @@ context("Tests for GroupedCharacter component", () => { ); }); + it.each([ + ["10%", "10%"], + ["30%", "30%"], + ["50%", "50%"], + ["80%", "80%"], + ["100%", "100%"], + ])( + "should use %s as maxWidth and render it with correct corresponding max-width percentage", + (input, totalWidth) => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", totalWidth); + } + ); + + it("as maxWidth has no value it should render as 100%", () => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", "100%"); + }); + describe("check events for GroupedCharacter component", () => { let callback; diff --git a/src/components/number/number.spec.js b/src/components/number/number.spec.js index 52c7c4123b..0860c5f029 100644 --- a/src/components/number/number.spec.js +++ b/src/components/number/number.spec.js @@ -3,6 +3,8 @@ import { mount } from "enzyme"; import Number from "./number.component"; import Textbox from "../textbox"; import Label from "../../__internal__/label"; +import { assertStyleMatch } from "../../__spec_helper__/test-utils"; +import InputPresentation from "../../__internal__/input/input-presentation.component"; describe("Number Input", () => { let wrapper, input, onChangeFn, onKeyDownFn; @@ -127,6 +129,29 @@ describe("Number Input", () => { expect(label.prop("isRequired")).toBe(true); }); }); + + describe("when maxWidth is passed", () => { + it("should be passed to InputPresentation", () => { + wrapper = renderNumberInput({ maxWidth: "67%" }); + + assertStyleMatch( + { + maxWidth: "67%", + }, + wrapper.find(InputPresentation) + ); + }); + + it("renders correctly as 100% as maxWidth has been left with no value", () => { + wrapper = renderNumberInput({ maxWidth: "" }); + assertStyleMatch( + { + maxWidth: "100%", + }, + wrapper.find(InputPresentation) + ); + }); + }); }); function renderNumberInput(props, renderer = mount) { diff --git a/src/components/number/number.stories.mdx b/src/components/number/number.stories.mdx index d2659cdb50..89fb4b134d 100644 --- a/src/components/number/number.stories.mdx +++ b/src/components/number/number.stories.mdx @@ -124,6 +124,18 @@ import Number from "carbon-react/lib/components/number"; +### With custom maxWidth + + + + + + + ### With fieldHelp diff --git a/src/components/number/number.test.js b/src/components/number/number.test.js index c621f6f780..cf9381d946 100644 --- a/src/components/number/number.test.js +++ b/src/components/number/number.test.js @@ -244,6 +244,33 @@ context("Tests for Number component", () => { ); }); + it.each([ + ["10%", "10%"], + ["30%", "30%"], + ["50%", "50%"], + ["80%", "80%"], + ["100%", "100%"], + ])( + "should use %s as maxWidth and render it with correct corresponding max-width percentage", + (input, totalWidth) => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", totalWidth); + } + ); + + it("as maxWidth has no value it should render as 100%", () => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", "100%"); + }); + describe("check events for Number component", () => { const inputValue = "1"; let callback; diff --git a/src/components/search/search.component.tsx b/src/components/search/search.component.tsx index 706fcc2cb7..42995febba 100644 --- a/src/components/search/search.component.tsx +++ b/src/components/search/search.component.tsx @@ -50,6 +50,11 @@ export interface SearchProps extends ValidationProps, MarginProps { * Leaving the `searchWidth` prop with no value will default the width to '100%' */ searchWidth?: string; + /** + * Prop for specifying the max width of the input. + * Leaving the `maxWidth` prop with no value will default the width to '100%' + */ + maxWidth?: string; /** Prop for active search threshold. This must be a positive number */ threshold?: number; /** Prop for `controlled` use */ @@ -74,6 +79,7 @@ export const Search = ({ name, threshold = 3, searchWidth, + maxWidth, searchButton, placeholder, variant = "default", @@ -229,6 +235,7 @@ export const Search = ({ ); -} - describe("Search", () => { let wrapper: ReactWrapper; let onBlur: jest.Mock; @@ -30,6 +26,10 @@ describe("Search", () => { testStyledSystemMargin((props) => ); + function renderSearch(props: SearchProps) { + return mount(); + } + describe("styles", () => { it("matches the expected styles", () => { assertStyleMatch( @@ -583,4 +583,24 @@ describe("Search", () => { expect(stopPropagationFn).not.toHaveBeenCalled(); }); }); + + describe("when maxWidth is passed", () => { + it("should be passed to InputPresentation", () => { + assertStyleMatch( + { + maxWidth: "67%", + }, + renderSearch({ value: "search", maxWidth: "67%" }) + ); + }); + + it("renders correctly as 100% as maxWidth has been left with no value", () => { + assertStyleMatch( + { + maxWidth: "100%", + }, + renderSearch({ value: "search", maxWidth: "" }) + ); + }); + }); }); diff --git a/src/components/search/search.stories.mdx b/src/components/search/search.stories.mdx index 67d5d23419..1011f3d3f5 100644 --- a/src/components/search/search.stories.mdx +++ b/src/components/search/search.stories.mdx @@ -141,6 +141,19 @@ In this example the `searchWidth` prop is 70%. +### With custom maxWidth + +In this example the `maxWidth` prop is 50%. + + + + + + + ### Search with Alternative Styling In this example the `variant` prop is "dark" and `searchButton` is true. diff --git a/src/components/search/search.style.ts b/src/components/search/search.style.ts index e0399c0c0a..5881806263 100644 --- a/src/components/search/search.style.ts +++ b/src/components/search/search.style.ts @@ -14,6 +14,7 @@ interface StyledSearchProps { searchHasValue?: boolean; searchIsActive?: boolean; searchWidth?: string; + maxWidth?: string; showSearchButton?: boolean; variant?: string; } @@ -22,6 +23,7 @@ const StyledSearch = styled.div` ${({ isFocused, searchWidth, + maxWidth, searchIsActive, searchHasValue, showSearchButton, @@ -41,6 +43,7 @@ const StyledSearch = styled.div` return css` ${margin} width: ${searchWidth ? `${searchWidth}` : "100%"}; + max-width: ${maxWidth ? `${maxWidth}` : "100%"}; padding-bottom: 2px; background-color: transparent; border-bottom: 2px solid ${variantColor}; diff --git a/src/components/search/search.test.js b/src/components/search/search.test.js index 1bc32ef760..2b6ec1948b 100644 --- a/src/components/search/search.test.js +++ b/src/components/search/search.test.js @@ -137,6 +137,38 @@ context("Test for Search component", () => { } ); + it.each([ + ["10%", "134px"], + ["34%", "458px"], + ["70%", "944px"], + ["100%", "1348px"], + ])( + "should render Search with maxWidth prop set to %s", + (widthInPercentage, widthVal) => { + CypressMountWithProviders( + + ); + + searchDefault().then(($el) => { + expect($el[0].getBoundingClientRect().width).to.be.within( + parseToIntElement(widthVal), + parseToIntElement(widthVal) + 2 + ); + }); + } + ); + + it("as maxWidth has no value it should render as 100%", () => { + CypressMountWithProviders(); + + searchDefault().then(($el) => { + expect($el[0].getBoundingClientRect().width).to.be.within( + parseToIntElement("1348"), + parseToIntElement("1348") + 2 + ); + }); + }); + it.each([ ["default", "rgb(102, 132, 148)"], ["dark", "rgb(153, 173, 183)"], diff --git a/src/components/select/filterable-select/filterable-select.spec.js b/src/components/select/filterable-select/filterable-select.spec.js index 35aa1abf3f..98f390800f 100644 --- a/src/components/select/filterable-select/filterable-select.spec.js +++ b/src/components/select/filterable-select/filterable-select.spec.js @@ -15,6 +15,7 @@ import Button from "../../button"; import Label from "../../../__internal__/label"; import InputIconToggle from "../../../__internal__/input-icon-toggle"; import guid from "../../../__internal__/utils/helpers/guid"; +import { InputPresentation } from "../../../__internal__/input"; jest.mock("../../../__internal__/utils/helpers/guid"); guid.mockImplementation(() => "guid-12345"); @@ -1046,6 +1047,30 @@ describe("coverage filler for else path", () => { wrapper.find("input").simulate("blur"); }); +describe("when maxWidth is passed", () => { + it("should be passed to InputPresentation", () => { + const wrapper = renderSelect({ maxWidth: "67%" }); + + assertStyleMatch( + { + maxWidth: "67%", + }, + wrapper.find(InputPresentation) + ); + }); + + it("renders correctly as 100% as maxWidth has been left with no value", () => { + const wrapper = renderSelect({ maxWidth: "" }); + + assertStyleMatch( + { + maxWidth: "100%", + }, + wrapper.find(InputPresentation) + ); + }); +}); + function renderSelect(props = {}, renderer = mount) { return renderer(getSelect(props)); } diff --git a/src/components/select/filterable-select/filterable-select.stories.mdx b/src/components/select/filterable-select/filterable-select.stories.mdx index 79d31d6061..b42b39fe54 100644 --- a/src/components/select/filterable-select/filterable-select.stories.mdx +++ b/src/components/select/filterable-select/filterable-select.stories.mdx @@ -614,6 +614,41 @@ This prop will be called every time a user scrolls to the bottom of the list. +### With custom maxWidth + +In this example the `maxWidth` prop is 50%. + + + + + + + + + ### Required You can use the `required` prop to indicate if the field is mandatory. diff --git a/src/components/select/filterable-select/filterable-select.test.js b/src/components/select/filterable-select/filterable-select.test.js index 2a02d7e58f..c717817b31 100644 --- a/src/components/select/filterable-select/filterable-select.test.js +++ b/src/components/select/filterable-select/filterable-select.test.js @@ -808,6 +808,35 @@ context("Tests for Filterable Select component", () => { } ); + it.each([ + ["10%", "10%"], + ["30%", "30%"], + ["50%", "50%"], + ["80%", "80%"], + ["100%", "100%"], + ])( + "should use %s as maxWidth and render it with correct corresponding max-width percentage", + (input, totalWidth) => { + CypressMountWithProviders( + + ); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", totalWidth); + } + ); + + it("as maxWidth has no value it should render as 100%", () => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", "100%"); + }); + it("should not open the list with focus on Filterable Select input", () => { CypressMountWithProviders(); diff --git a/src/components/select/multi-select/multi-select.spec.js b/src/components/select/multi-select/multi-select.spec.js index b0e042f97b..29809547b2 100644 --- a/src/components/select/multi-select/multi-select.spec.js +++ b/src/components/select/multi-select/multi-select.spec.js @@ -14,6 +14,7 @@ import { StyledSelectList } from "../select-list/select-list.style"; import Pill from "../../pill"; import Label from "../../../__internal__/label"; import InputPresentationStyle from "../../../__internal__/input/input-presentation.style"; +import { InputPresentation } from "../../../__internal__/input"; describe("MultiSelect", () => { testStyledSystemMargin((props) => getSelect(props)); @@ -1006,6 +1007,30 @@ describe("coverage filler for else path", () => { wrapper.find("input").simulate("blur"); }); +describe("when maxWidth is passed", () => { + it("should be passed to InputPresentation", () => { + const wrapper = renderSelect({ maxWidth: "67%" }); + + assertStyleMatch( + { + maxWidth: "67%", + }, + wrapper.find(InputPresentation) + ); + }); + + it("renders correctly as 100% as maxWidth has been left with no value", () => { + const wrapper = renderSelect({ maxWidth: "" }); + + assertStyleMatch( + { + maxWidth: "100%", + }, + wrapper.find(InputPresentation) + ); + }); +}); + function renderSelect(props = {}, renderer = mount) { return renderer(getSelect(props)); } diff --git a/src/components/select/multi-select/multi-select.stories.mdx b/src/components/select/multi-select/multi-select.stories.mdx index 7f21a117a9..644e943e3b 100644 --- a/src/components/select/multi-select/multi-select.stories.mdx +++ b/src/components/select/multi-select/multi-select.stories.mdx @@ -520,6 +520,33 @@ See Colors +### With custom maxWidth + +In this example the `maxWidth` prop is 50%. + + + + + + + + #### New designs validation diff --git a/src/components/select/multi-select/multi-select.test.js b/src/components/select/multi-select/multi-select.test.js index 34bd3220f3..ab991c23e5 100644 --- a/src/components/select/multi-select/multi-select.test.js +++ b/src/components/select/multi-select/multi-select.test.js @@ -700,6 +700,33 @@ context("Tests for Multi Select component", () => { } ); + it.each([ + ["10%", "10%"], + ["30%", "30%"], + ["50%", "50%"], + ["80%", "80%"], + ["100%", "100%"], + ])( + "should use %s as maxWidth and render it with correct corresponding max-width percentage", + (input, totalWidth) => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", totalWidth); + } + ); + + it("as maxWidth has no value it should render as 100%", () => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", "100%"); + }); + it("should not open the list with focus on Multi Select input", () => { CypressMountWithProviders(); diff --git a/src/components/select/simple-select/simple-select.spec.js b/src/components/select/simple-select/simple-select.spec.js index 736ca04460..126b02b82d 100644 --- a/src/components/select/simple-select/simple-select.spec.js +++ b/src/components/select/simple-select/simple-select.spec.js @@ -14,6 +14,7 @@ import { StyledSelectList } from "../select-list/select-list.style"; import InputIconToggleStyle from "../../../__internal__/input-icon-toggle/input-icon-toggle.style"; import InputPresentationStyle from "../../../__internal__/input/input-presentation.style"; import Label from "../../../__internal__/label"; +import { InputPresentation } from "../../../__internal__/input"; describe("SimpleSelect", () => { describe("when an HTML element is clicked when the SelectList is open", () => { @@ -846,6 +847,30 @@ describe("coverage filler for else path", () => { simulateKeyDown(wrapper, "F1"); }); +describe("when maxWidth is passed", () => { + it("should be passed to InputPresentation", () => { + const wrapper = renderSelect({ maxWidth: "67%" }); + + assertStyleMatch( + { + maxWidth: "67%", + }, + wrapper.find(InputPresentation) + ); + }); + + it("renders correctly as 100% as maxWidth has been left with no value", () => { + const wrapper = renderSelect({ maxWidth: "" }); + + assertStyleMatch( + { + maxWidth: "100%", + }, + wrapper.find(InputPresentation) + ); + }); +}); + function simulateKeyDown(container, key, options = {}) { const selectText = container.find("[data-element='select-text']").first(); diff --git a/src/components/select/simple-select/simple-select.stories.mdx b/src/components/select/simple-select/simple-select.stories.mdx index 6fa8ad244d..4c2d5ff71b 100644 --- a/src/components/select/simple-select/simple-select.stories.mdx +++ b/src/components/select/simple-select/simple-select.stories.mdx @@ -280,6 +280,28 @@ If there is no `id` prop specified on an object, then the exact objects will be +### With custom maxWidth + +In this example the `maxWidth` prop is 100%. + + + + + + + ### With isLoading prop When `isLoading` prop is passed, a loader will be appended at the end of the Select List. That functionality could be used to load the options asynchronously. diff --git a/src/components/select/simple-select/simple-select.test.js b/src/components/select/simple-select/simple-select.test.js index 66cd025897..edb664d346 100644 --- a/src/components/select/simple-select/simple-select.test.js +++ b/src/components/select/simple-select/simple-select.test.js @@ -671,6 +671,33 @@ context("Tests for Simple Select component", () => { } ); + it.each([ + ["10%", "10%"], + ["30%", "30%"], + ["50%", "50%"], + ["80%", "80%"], + ["100%", "100%"], + ])( + "should use %s as maxWidth and render it with correct corresponding max-width percentage", + (input, totalWidth) => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", totalWidth); + } + ); + + it("as maxWidth has no value it should render as 100%", () => { + CypressMountWithProviders(); + + getDataElementByValue("input") + .parent() + .parent() + .should("have.css", "max-width", "100%"); + }); + it("should open the list with mouse click on Select input", () => { CypressMountWithProviders(); diff --git a/src/components/textarea/textarea-test.stories.tsx b/src/components/textarea/textarea-test.stories.tsx index 7695ce0c7a..a6971d19b8 100644 --- a/src/components/textarea/textarea-test.stories.tsx +++ b/src/components/textarea/textarea-test.stories.tsx @@ -103,6 +103,11 @@ export default { type: "number", }, }, + maxWidth: { + control: { + type: "text", + }, + }, }, args: { expandable: false, diff --git a/src/components/textarea/textarea.component.tsx b/src/components/textarea/textarea.component.tsx index 5b4cdbf15e..3e6f751ccf 100644 --- a/src/components/textarea/textarea.component.tsx +++ b/src/components/textarea/textarea.component.tsx @@ -69,6 +69,11 @@ export interface TextareaProps inputIcon?: IconType; /** Width of an input in percentage. Works only when labelInline is true */ inputWidth?: number; + /** + * Prop for specifying the max width of the input. + * Leaving the `maxWidth` prop with no value will default the width to '100%' + */ + maxWidth?: string; /** The content of the label for the input */ label?: string; /** Inline label alignment */ @@ -140,6 +145,7 @@ export const Textarea = ({ validationOnLabel = false, adaptiveLabelBreakpoint, inputWidth, + maxWidth, labelWidth = 30, tooltipPosition, value, @@ -235,6 +241,7 @@ export const Textarea = ({ inputWidth={ typeof inputWidth === "number" ? inputWidth : 100 - labelWidth } + maxWidth={maxWidth} error={error} warning={warning} info={info} diff --git a/src/components/textarea/textarea.spec.tsx b/src/components/textarea/textarea.spec.tsx index 5176ef452d..8d05fcf453 100644 --- a/src/components/textarea/textarea.spec.tsx +++ b/src/components/textarea/textarea.spec.tsx @@ -375,6 +375,29 @@ describe("Textarea", () => { expect(wrapper.find(InputPresentation).props().inputWidth).toBe(55); }); }); + + describe("when maxWidth is passed", () => { + it("should be passed to InputPresentation", () => { + wrapper = renderTextarea({ maxWidth: "67%" }); + + assertStyleMatch( + { + maxWidth: "67%", + }, + wrapper.find(InputPresentation) + ); + }); + + it("renders correctly as 100% as maxWidth has been left with no value", () => { + wrapper = renderTextarea({ maxWidth: "" }); + assertStyleMatch( + { + maxWidth: "100%", + }, + wrapper.find(InputPresentation) + ); + }); + }); }); describe("componentWillUnmount", () => { diff --git a/src/components/textarea/textarea.stories.mdx b/src/components/textarea/textarea.stories.mdx index 969124f2f9..03f3e3b299 100644 --- a/src/components/textarea/textarea.stories.mdx +++ b/src/components/textarea/textarea.stories.mdx @@ -102,6 +102,17 @@ import Textarea from "carbon-react/lib/components/textarea"; /> +### With custom maxWidth + + + +