diff --git a/CHANGELOG.md b/CHANGELOG.md index b0ce63a9b25..87104d2fe66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Added `repositionOnScroll` prop to `EuiPopover` which enables repositioning the popover when the window is scrolled. ([#1064](https://github.com/elastic/eui/pull/1064)) - Allow `_` and `*` characters to be used in `EuiSearchBar` query terms ([#1058](https://github.com/elastic/eui/pull/1058)) - Added more `status` options for `EuiSteps` ([#1088](https://github.com/elastic/eui/pull/1088)) +- Added `maxWidth` prop `EuiFlyout` ([#1090](https://github.com/elastic/eui/pull/1090)) +- Added `string` to allowed `restrictWidth` prop type of `EuiPage` and `EuiPageBody` ([#1090](https://github.com/elastic/eui/pull/1090)) **Bug fixes** @@ -15,6 +17,7 @@ - Fixed `EuiBasicTable` to inform its parent about a selection change triggered by a different set of `items` ([#1086](https://github.com/elastic/eui/pull/1086)) - Fixed width of `EuiFilterGroup`'s popover ([#1078](https://github.com/elastic/eui/pull/1078)) - Fixed `EuiStepsHorizontal`'s title wrapping in IE ([#1088](https://github.com/elastic/eui/pull/1088)) +- Fixed wrong class name being added to `EuiPageBody` when `restrictWidth !== false` ([#1090](https://github.com/elastic/eui/pull/1090)) ## [`3.3.0`](https://github.com/elastic/eui/tree/v3.3.0) diff --git a/src-docs/src/views/flyout/flyout_example.js b/src-docs/src/views/flyout/flyout_example.js index bc2ebb63339..ad91f436ec1 100644 --- a/src-docs/src/views/flyout/flyout_example.js +++ b/src-docs/src/views/flyout/flyout_example.js @@ -2,16 +2,9 @@ import React from 'react'; import { renderToHtml } from '../../services'; -import { - GuideSectionTypes, -} from '../../components'; +import { GuideSectionTypes } from '../../components'; -import { - EuiCode, - EuiFlyout, - EuiFlyoutHeader, - EuiFlyoutFooter, -} from '../../../../src/components'; +import { EuiCode, EuiFlyout, EuiFlyoutHeader, EuiFlyoutFooter } from '../../../../src/components'; import { Flyout } from './flyout'; const flyoutSource = require('!!raw-loader!./flyout'); @@ -29,36 +22,43 @@ export const FlyoutExample = { title: 'Flyout', sections: [ { - source: [{ - type: GuideSectionTypes.JS, - code: flyoutSource, - }, { - type: GuideSectionTypes.HTML, - code: flyoutHtml, - }], + source: [ + { + type: GuideSectionTypes.JS, + code: flyoutSource, + }, + { + type: GuideSectionTypes.HTML, + code: flyoutHtml, + }, + ], text: ( <div> <p> - <EuiCode>EuiFlyout</EuiCode> is a fixed position panel that pops in - from the right side of the screen. It should be used any time you - need to perform quick, individual actions to a larger page or list. + <EuiCode>EuiFlyout</EuiCode> is a fixed position panel that pops in from the right side + of the screen. It should be used any time you need to perform quick, individual actions + to a larger page or list. </p> <ul> <li> - <EuiCode>size</EuiCode> accepts <EuiCode>s / m / l</EuiCode> and - defines the width of the panel. + <EuiCode>size</EuiCode> accepts <EuiCode>s / m / l</EuiCode> and defines the width of + the panel. </li> <li> - <EuiCode>ownFocus</EuiCode> is a boolean that - when <EuiCode>true</EuiCode> will lock the mouse / keyboard focus - to within the flyout. It is off by default. + <EuiCode>ownFocus</EuiCode> is a boolean that when <EuiCode>true</EuiCode> will lock + the mouse / keyboard focus to within the flyout. It is off by default. + </li> + <li> + <EuiCode>maxWidth</EuiCode> accepts a boolean or number. When set to{' '} + <EuiCode>true</EuiCode>, it adds a predefined maxWidth or you can pass an integer set + the max width to a custom pixel value or a string to set it to a custom measurement. </li> </ul> <p> - Notice how these examples use <EuiCode>aria-labelledby</EuiCode> to - announce the flyout to screen readers when the user opens it. + Notice how these examples use <EuiCode>aria-labelledby</EuiCode> to announce the flyout + to screen readers when the user opens it. </p> </div> ), @@ -67,19 +67,22 @@ export const FlyoutExample = { }, { title: 'More complicated Flyout', - source: [{ - type: GuideSectionTypes.JS, - code: flyoutComplicatedSource, - }, { - type: GuideSectionTypes.HTML, - code: flyoutComplicatedHtml, - }], + source: [ + { + type: GuideSectionTypes.JS, + code: flyoutComplicatedSource, + }, + { + type: GuideSectionTypes.HTML, + code: flyoutComplicatedHtml, + }, + ], text: ( <p> In this example we use <EuiCode>EuiFlyoutHeader</EuiCode> and - <EuiCode>EuiFlyoutFooter</EuiCode> to allow for fixed position navigation - and actions within a flyout. Note that any content - within <EuiCode>EuiContentBody</EuiCode> will automatcially overflow. + <EuiCode>EuiFlyoutFooter</EuiCode> to allow for fixed position navigation and actions + within a flyout. Note that any content within <EuiCode>EuiContentBody</EuiCode> will + automatcially overflow. </p> ), props: { EuiFlyoutFooter }, @@ -87,19 +90,21 @@ export const FlyoutExample = { }, { title: 'Flyout sizing and focus', - source: [{ - type: GuideSectionTypes.JS, - code: flyoutSizeSource, - }, { - type: GuideSectionTypes.HTML, - code: flyoutSizeHtml, - }], + source: [ + { + type: GuideSectionTypes.JS, + code: flyoutSizeSource, + }, + { + type: GuideSectionTypes.HTML, + code: flyoutSizeHtml, + }, + ], text: ( <p> - In this example, we set <EuiCode>size</EuiCode> to <EuiCode>s</EuiCode> and - apply the <EuiCode>ownFocus</EuiCode> prop. The latter not only traps the - focus of our flyout, but also adds background overlay to reinforce your - boundries. + In this example, we set <EuiCode>size</EuiCode> to <EuiCode>s</EuiCode> and apply the{' '} + <EuiCode>ownFocus</EuiCode> prop. The latter not only traps the focus of our flyout, but + also adds background overlay to reinforce your boundries. </p> ), demo: <FlyoutSize />, diff --git a/src-docs/src/views/page/page_example.js b/src-docs/src/views/page/page_example.js index 7893ff9b818..56acc063a3e 100644 --- a/src-docs/src/views/page/page_example.js +++ b/src-docs/src/views/page/page_example.js @@ -2,9 +2,7 @@ import React from 'react'; import { renderToHtml } from '../../services'; -import { - GuideSectionTypes, -} from '../../components'; +import { GuideSectionTypes } from '../../components'; import { EuiCode, @@ -41,105 +39,140 @@ const PageContentCenterWithSideBarHtml = renderToHtml(Page); export const PageExample = { title: 'Page', - sections: [{ - title: 'Page with everything on', - source: [{ - type: GuideSectionTypes.JS, - code: pageSource, - }, { - type: GuideSectionTypes.HTML, - code: pageHtml, - }], - text: ( - <div> + sections: [ + { + title: 'Page with everything on', + source: [ + { + type: GuideSectionTypes.JS, + code: pageSource, + }, + { + type: GuideSectionTypes.HTML, + code: pageHtml, + }, + ], + text: ( + <div> + <p> + Page layouts are modular and have the ability to add or remove components as needed for + the design. These examples are colored for illustrative purposes only. + </p> + <p> + By default, the entire page will always be 100% of the window's width, to max this + out the typical width and center the page, set the <EuiCode>restrictWidth</EuiCode> prop + to <EuiCode>true</EuiCode>. You can also pass an integer to this property to max out the + width at a custom pixel value or a string with a custom measurement. + </p> + </div> + ), + props: { + EuiPage, + EuiPageBody, + EuiPageContent, + EuiPageContentBody, + EuiPageContentHeader, + EuiPageContentHeaderSection, + EuiPageHeader, + EuiPageHeaderSection, + EuiPageSideBar, + }, + demo: ( + <div className="guideDemo__highlightLayout"> + <Page /> + </div> + ), + }, + { + title: 'Simple page with title', + source: [ + { + type: GuideSectionTypes.JS, + code: pageSimpleSource, + }, + { + type: GuideSectionTypes.HTML, + code: pageSimpleHtml, + }, + ], + text: ( <p> - Page layouts are modular and have the ability to add or remove components - as needed for the design. These examples are colored for illustrative - purposes only. + Most pages don’t have sidebars. A lot of our pages don’t have extra abilities + next to the title. Simply exclude those components and everything will still line up. </p> + ), + demo: ( + <div className="guideDemo__highlightLayout"> + <PageSimple /> + </div> + ), + }, + { + title: 'Page with content only', + source: [ + { + type: GuideSectionTypes.JS, + code: pageContentOnlySource, + }, + { + type: GuideSectionTypes.HTML, + code: pageContentOnlyHtml, + }, + ], + text: <p>We can further simplify pages by only showing the content.</p>, + demo: ( + <div className="guideDemo__highlightLayout"> + <PageContentOnly /> + </div> + ), + }, + { + title: 'Page content centered', + source: [ + { + type: GuideSectionTypes.JS, + code: pageContentCenterSource, + }, + { + type: GuideSectionTypes.HTML, + code: pageContentCenterHtml, + }, + ], + text: ( + <p> + The page content can be optionally centered either vertically or horizontally. This is + useful for various empty states. + </p> + ), + demo: ( + <div className="guideDemo__highlightLayout"> + <PageContentCenter /> + </div> + ), + }, + { + title: 'Page content centered in a full layout', + source: [ + { + type: GuideSectionTypes.JS, + code: PageContentCenterWithSideBarSource, + }, + { + type: GuideSectionTypes.HTML, + code: PageContentCenterWithSideBarHtml, + }, + ], + text: ( <p> - By default, the entire page will always be 100% of the window's width, - to max this out the typical width and center the page, set - the <EuiCode>restrictWidth</EuiCode> prop to <EuiCode>true</EuiCode>. You - can also pass an integer to this property to max out the width at a custom - size. + Centering the content can happen regardless of layout configuration. In this example, + we’re cetnering within a complex sidebar layout. </p> - </div> - ), - props: { - EuiPage, - EuiPageBody, - EuiPageContent, - EuiPageContentBody, - EuiPageContentHeader, - EuiPageContentHeaderSection, - EuiPageHeader, - EuiPageHeaderSection, - EuiPageSideBar, + ), + demo: ( + <div className="guideDemo__highlightLayout"> + <PageContentCenterWithSideBar /> + </div> + ), }, - demo: <div className="guideDemo__highlightLayout"><Page /></div>, - }, { - title: 'Simple page with title', - source: [{ - type: GuideSectionTypes.JS, - code: pageSimpleSource, - }, { - type: GuideSectionTypes.HTML, - code: pageSimpleHtml, - }], - text: ( - <p> - Most pages don’t have sidebars. A lot of our pages don’t have extra abilities next to the title. - Simply exclude those components and everything will still line up. - </p> - ), - demo: <div className="guideDemo__highlightLayout"><PageSimple /></div>, - }, { - title: 'Page with content only', - source: [{ - type: GuideSectionTypes.JS, - code: pageContentOnlySource, - }, { - type: GuideSectionTypes.HTML, - code: pageContentOnlyHtml, - }], - text: ( - <p> - We can further simplify pages by only showing the content. - </p> - ), - demo: <div className="guideDemo__highlightLayout"><PageContentOnly /></div>, - }, { - title: 'Page content centered', - source: [{ - type: GuideSectionTypes.JS, - code: pageContentCenterSource, - }, { - type: GuideSectionTypes.HTML, - code: pageContentCenterHtml, - }], - text: ( - <p> - The page content can be optionally centered either vertically - or horizontally. This is useful for various empty states. - </p> - ), - demo: <div className="guideDemo__highlightLayout"><PageContentCenter /></div>, - }, { - title: 'Page content centered in a full layout', - source: [{ - type: GuideSectionTypes.JS, - code: PageContentCenterWithSideBarSource, - }, { - type: GuideSectionTypes.HTML, - code: PageContentCenterWithSideBarHtml, - }], - text: ( - <p> - Centering the content can happen regardless of layout configuration. - In this example, we’re cetnering within a complex sidebar layout. - </p> - ), - demo: <div className="guideDemo__highlightLayout"><PageContentCenterWithSideBar /></div>, - }], + ], }; diff --git a/src/components/flyout/__snapshots__/flyout.test.js.snap b/src/components/flyout/__snapshots__/flyout.test.js.snap index e1acc04f82e..f3178669bb2 100644 --- a/src/components/flyout/__snapshots__/flyout.test.js.snap +++ b/src/components/flyout/__snapshots__/flyout.test.js.snap @@ -43,6 +43,131 @@ exports[`EuiFlyout is rendered 1`] = ` </span> `; +exports[`EuiFlyout max width can be set to a custom number 1`] = ` +<span> + <div> + <div + class="euiFlyout euiFlyout--medium" + role="dialog" + style="max-width:1024px" + tabindex="0" + > + <button + aria-label="Closes this dialog" + class="euiButtonIcon euiButtonIcon--text euiFlyout__closeButton" + data-test-subj="euiFlyoutCloseButton" + type="button" + > + <svg + aria-hidden="true" + class="euiIcon euiIcon--medium euiButtonIcon__icon" + focusable="false" + height="16" + viewBox="0 0 16 16" + width="16" + xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + > + <defs> + <path + d="M7.293 8l-4.147 4.146a.5.5 0 0 0 .708.708L8 8.707l4.146 4.147a.5.5 0 0 0 .708-.708L8.707 8l4.147-4.146a.5.5 0 0 0-.708-.708L8 7.293 3.854 3.146a.5.5 0 1 0-.708.708L7.293 8z" + id="cross-a" + /> + </defs> + <use + fill-rule="nonzero" + href="#cross-a" + /> + </svg> + </button> + </div> + </div> +</span> +`; + +exports[`EuiFlyout max width can be set to a custom value and measurement 1`] = ` +<span> + <div> + <div + class="euiFlyout euiFlyout--medium" + role="dialog" + style="max-width:24rem" + tabindex="0" + > + <button + aria-label="Closes this dialog" + class="euiButtonIcon euiButtonIcon--text euiFlyout__closeButton" + data-test-subj="euiFlyoutCloseButton" + type="button" + > + <svg + aria-hidden="true" + class="euiIcon euiIcon--medium euiButtonIcon__icon" + focusable="false" + height="16" + viewBox="0 0 16 16" + width="16" + xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + > + <defs> + <path + d="M7.293 8l-4.147 4.146a.5.5 0 0 0 .708.708L8 8.707l4.146 4.147a.5.5 0 0 0 .708-.708L8.707 8l4.147-4.146a.5.5 0 0 0-.708-.708L8 7.293 3.854 3.146a.5.5 0 1 0-.708.708L7.293 8z" + id="cross-a" + /> + </defs> + <use + fill-rule="nonzero" + href="#cross-a" + /> + </svg> + </button> + </div> + </div> +</span> +`; + +exports[`EuiFlyout max width can be set to a default 1`] = ` +<span> + <div> + <div + class="euiFlyout euiFlyout--medium euiFlyout--maxWidth-default" + role="dialog" + tabindex="0" + > + <button + aria-label="Closes this dialog" + class="euiButtonIcon euiButtonIcon--text euiFlyout__closeButton" + data-test-subj="euiFlyoutCloseButton" + type="button" + > + <svg + aria-hidden="true" + class="euiIcon euiIcon--medium euiButtonIcon__icon" + focusable="false" + height="16" + viewBox="0 0 16 16" + width="16" + xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + > + <defs> + <path + d="M7.293 8l-4.147 4.146a.5.5 0 0 0 .708.708L8 8.707l4.146 4.147a.5.5 0 0 0 .708-.708L8.707 8l4.147-4.146a.5.5 0 0 0-.708-.708L8 7.293 3.854 3.146a.5.5 0 1 0-.708.708L7.293 8z" + id="cross-a" + /> + </defs> + <use + fill-rule="nonzero" + href="#cross-a" + /> + </svg> + </button> + </div> + </div> +</span> +`; + exports[`EuiFlyout props close button is not rendered 1`] = ` <span> <div> diff --git a/src/components/flyout/_flyout.scss b/src/components/flyout/_flyout.scss index 72b34e768d6..b10ebc707be 100644 --- a/src/components/flyout/_flyout.scss +++ b/src/components/flyout/_flyout.scss @@ -30,15 +30,18 @@ $flyoutSizes: ( "small": ( min: map-get($euiBreakpoints, "m") * .5, /* 1 */ - width: 25vw + width: 25vw, + max: map-get($euiBreakpoints, "s"), ), "medium": ( min: map-get($euiBreakpoints, "m") * .7, /* 1 */ - width: 50vw + width: 50vw, + max: map-get($euiBreakpoints, "m"), ), "large": ( min: map-get($euiBreakpoints, "m") * .9, /* 1 */ - width: 75vw + width: 75vw, + max: map-get($euiBreakpoints, "l"), ) ); @@ -46,6 +49,10 @@ $flyoutSizes: ( .euiFlyout--#{$name} { min-width: map-get($sizing, min); width: map-get($sizing, width); + + &.euiFlyout--maxWidth-default { + max-width: map-get($sizing, max); + } } } diff --git a/src/components/flyout/flyout.js b/src/components/flyout/flyout.js index abf031b280d..251b8961066 100644 --- a/src/components/flyout/flyout.js +++ b/src/components/flyout/flyout.js @@ -34,10 +34,21 @@ export class EuiFlyout extends Component { ownFocus, size, closeButtonAriaLabel, + maxWidth, + style, ...rest } = this.props; - const classes = classnames('euiFlyout', sizeToClassNameMap[size], className); + let newStyle; + let widthClassName; + if (maxWidth === true) { + widthClassName = 'euiFlyout--maxWidth-default'; + } else if (maxWidth !== false) { + const value = typeof maxWidth === 'number' ? `${maxWidth}px` : maxWidth; + newStyle = { ...style, maxWidth: value }; + } + + const classes = classnames('euiFlyout', sizeToClassNameMap[size], widthClassName, className); let closeButton; if (onClose && !hideCloseButton) { @@ -62,6 +73,7 @@ export class EuiFlyout extends Component { className={classes} tabIndex={0} onKeyDown={this.onKeyDown} + style={newStyle || style} {...rest} > {closeButton} @@ -111,6 +123,18 @@ EuiFlyout.propTypes = { * Specify an aria-label for the close button of the flyout */ closeButtonAriaLabel: PropTypes.string, + /** + * Sets the max-width of the page, + * set to `true` to use the default size, + * set to `false` to not restrict the width, + * set to a number for a custom width in px, + * set to a string for a custom width in custom measurement. + */ + maxWidth: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.number, + PropTypes.string, + ]), }; EuiFlyout.defaultProps = { @@ -118,4 +142,5 @@ EuiFlyout.defaultProps = { hideCloseButton: false, ownFocus: false, closeButtonAriaLabel: 'Closes this dialog', + maxWidth: false, }; diff --git a/src/components/flyout/flyout.test.js b/src/components/flyout/flyout.test.js index a24395a6774..046973fa87b 100644 --- a/src/components/flyout/flyout.test.js +++ b/src/components/flyout/flyout.test.js @@ -57,7 +57,6 @@ describe('EuiFlyout', () => { }); }); - describe('size', () => { SIZES.forEach(size => { it(`${size} is rendered`, () => { @@ -73,4 +72,42 @@ describe('EuiFlyout', () => { }); }); }); + + describe('max width', () => { + test('can be set to a default', () => { + const component = render( + <EuiFlyout + onClose={() => {}} + maxWidth={true} + /> + ); + + expect(component) + .toMatchSnapshot(); + }); + + test('can be set to a custom number', () => { + const component = render( + <EuiFlyout + onClose={() => {}} + maxWidth={1024} + /> + ); + + expect(component) + .toMatchSnapshot(); + }); + + test('can be set to a custom value and measurement', () => { + const component = render( + <EuiFlyout + onClose={() => {}} + maxWidth="24rem" + /> + ); + + expect(component) + .toMatchSnapshot(); + }); + }); }); diff --git a/src/components/flyout/index.d.ts b/src/components/flyout/index.d.ts index 00ed8058b79..918a526f2e2 100644 --- a/src/components/flyout/index.d.ts +++ b/src/components/flyout/index.d.ts @@ -14,6 +14,14 @@ declare module '@elastic/eui' { * Specify an aria-label for the close button of the flyout. */ closeButtonAriaLabel?: string; + /** + * Sets the max-width of the page, + * set to `true` to use the default size, + * set to `false` to not restrict the width, + * set to a number for a custom width in px, + * set to a string for a custom width in custom measurement. + */ + maxWidth?: boolean | number | string; } export const EuiFlyout: React.SFC< diff --git a/src/components/page/__snapshots__/page.test.js.snap b/src/components/page/__snapshots__/page.test.js.snap index 923def06dd4..622d924aabd 100644 --- a/src/components/page/__snapshots__/page.test.js.snap +++ b/src/components/page/__snapshots__/page.test.js.snap @@ -3,12 +3,12 @@ exports[`EuiPage is rendered 1`] = ` <div aria-label="aria-label" - class="euiPage euiPage--widthIsNotRestricted testClass1 testClass2" + class="euiPage testClass1 testClass2" data-test-subj="test subject string" /> `; -exports[`EuiPage sets a max-width 1`] = ` +exports[`EuiPage restrict width can be set to a custom number 1`] = ` <div aria-label="aria-label" class="euiPage euiPage--restrictWidth-custom testClass1 testClass2" @@ -16,3 +16,20 @@ exports[`EuiPage sets a max-width 1`] = ` style="max-width:1024px" /> `; + +exports[`EuiPage restrict width can be set to a custom value and measurement 1`] = ` +<div + aria-label="aria-label" + class="euiPage euiPage--restrictWidth-custom testClass1 testClass2" + data-test-subj="test subject string" + style="max-width:24rem" +/> +`; + +exports[`EuiPage restrict width can be set to a default 1`] = ` +<div + aria-label="aria-label" + class="euiPage euiPage--restrictWidth-default testClass1 testClass2" + data-test-subj="test subject string" +/> +`; diff --git a/src/components/page/index.d.ts b/src/components/page/index.d.ts index 286a42af198..f8b538df508 100644 --- a/src/components/page/index.d.ts +++ b/src/components/page/index.d.ts @@ -4,38 +4,36 @@ import { SFC, HTMLAttributes } from 'react'; declare module '@elastic/eui' { + export interface EuiPageWidthProps { + /** + * Sets the max-width of the page, + * set to `true` to use the default size, + * set to `false` to not restrict the width, + * set to a number for a custom width in px, + * set to a string for a custom width in custom measurement. + */ + restrictWidth?: boolean | number | string; + } /** * @see './page.js' */ - export const EuiPage: SFC< - CommonProps & HTMLAttributes<HTMLDivElement> - >; - + export const EuiPage: SFC<CommonProps & EuiPageWidthProps &HTMLAttributes<HTMLDivElement>>; /** * @see ./page_header/page_header.js */ - export const EuiPageHeader: SFC< - CommonProps & HTMLAttributes<HTMLDivElement> - >; - + export const EuiPageHeader: SFC<CommonProps & HTMLAttributes<HTMLDivElement>>; /** * @see ./page_header/page_header_section.js */ - export const EuiPageHeaderSection: SFC< - CommonProps & HTMLAttributes<HTMLDivElement> - >; - + export const EuiPageHeaderSection: SFC<CommonProps & HTMLAttributes<HTMLDivElement>>; /** * @see ./page_body/page_body.js */ - export const EuiPageBody: SFC< - CommonProps & HTMLAttributes<HTMLDivElement> - >; - + export const EuiPageBody: SFC<CommonProps & EuiPageWidthProps & HTMLAttributes<HTMLDivElement>>; /** * @see ./page_content/page_content.js @@ -51,39 +49,25 @@ declare module '@elastic/eui' { horizontalPosition?: EuiPageContentHorizontalPosition; } - export const EuiPageContent: SFC< - CommonProps & EuiPanelProps & EuiPageContentProps - >; - + export const EuiPageContent: SFC<CommonProps & EuiPanelProps & EuiPageContentProps>; /** * @see ./page_content/page_content_body.js */ - export const EuiPageContentBody: SFC< - CommonProps & HTMLAttributes<HTMLDivElement> - >; - + export const EuiPageContentBody: SFC<CommonProps & HTMLAttributes<HTMLDivElement>>; /** * @see ./page_content/page_content_header.js */ - export const EuiPageContentHeader: SFC< - CommonProps & HTMLAttributes<HTMLDivElement> - >; - + export const EuiPageContentHeader: SFC<CommonProps & HTMLAttributes<HTMLDivElement>>; /** * @see ./page_content/page_content_header_section.js */ - export const EuiPageContentHeaderSection: SFC< - CommonProps & HTMLAttributes<HTMLDivElement> - >; + export const EuiPageContentHeaderSection: SFC<CommonProps & HTMLAttributes<HTMLDivElement>>; /** * @see ./page_side_bar/page_side_bar.js */ - export const EuiPageSideBar: SFC< - CommonProps & HTMLAttributes<HTMLDivElement> - >; - + export const EuiPageSideBar: SFC<CommonProps & HTMLAttributes<HTMLDivElement>>; } diff --git a/src/components/page/page.js b/src/components/page/page.js index a4ba36dd1e4..e93b90c8a76 100644 --- a/src/components/page/page.js +++ b/src/components/page/page.js @@ -4,22 +4,14 @@ import classNames from 'classnames'; export const EuiPage = ({ children, className, restrictWidth, style, ...rest }) => { let widthClassname; + let newStyle; if (restrictWidth === true) { widthClassname = 'euiPage--restrictWidth-default'; - } else if (restrictWidth === false) { - widthClassname = 'euiPage--widthIsNotRestricted'; - } else { + } else if (restrictWidth !== false) { widthClassname = 'euiPage--restrictWidth-custom'; - - // if style has been passed as a prop, add to it - if (style) { - style.maxWidth = `${restrictWidth}px`; - } - // otherwise create a new object - else { - style = { maxWidth: `${restrictWidth}px` }; - } + const value = typeof maxWidth === 'number' ? `${restrictWidth}px` : restrictWidth; + newStyle = { ...style, maxWidth: value }; } const classes = classNames( @@ -31,7 +23,7 @@ export const EuiPage = ({ children, className, restrictWidth, style, ...rest }) return ( <div className={classes} - style={style} + style={newStyle || style} {...rest} > {children} @@ -47,11 +39,13 @@ EuiPage.propTypes = { * Sets the max-width of the page, * set to `true` to use the default size, * set to `false` to not restrict the width, - * set to a number for a custom width. + * set to a number for a custom width in px, + * set to a string for a custom width in custom measurement. */ restrictWidth: PropTypes.oneOfType([ PropTypes.bool, - PropTypes.number + PropTypes.number, + PropTypes.string, ]), }; diff --git a/src/components/page/page.test.js b/src/components/page/page.test.js index 98bac1462a8..3c0d895bc7e 100644 --- a/src/components/page/page.test.js +++ b/src/components/page/page.test.js @@ -6,20 +6,28 @@ import { EuiPage } from './page'; describe('EuiPage', () => { test('is rendered', () => { - const component = render( - <EuiPage {...requiredProps} /> - ); + const component = render(<EuiPage {...requiredProps} />); - expect(component) - .toMatchSnapshot(); + expect(component).toMatchSnapshot(); }); - test('sets a max-width', () => { - const component = render( - <EuiPage {...requiredProps} restrictWidth={1024} /> - ); + describe('restrict width', () => { + test('can be set to a default', () => { + const component = render(<EuiPage {...requiredProps} restrictWidth={true} />); - expect(component) - .toMatchSnapshot(); + expect(component).toMatchSnapshot(); + }); + + test('can be set to a custom number', () => { + const component = render(<EuiPage {...requiredProps} restrictWidth={1024} />); + + expect(component).toMatchSnapshot(); + }); + + test('can be set to a custom value and measurement', () => { + const component = render(<EuiPage {...requiredProps} restrictWidth="24rem" />); + + expect(component).toMatchSnapshot(); + }); }); }); diff --git a/src/components/page/page_body/__snapshots__/page_body.test.js.snap b/src/components/page/page_body/__snapshots__/page_body.test.js.snap index 35574c6eb50..e9b1a25ef9f 100644 --- a/src/components/page/page_body/__snapshots__/page_body.test.js.snap +++ b/src/components/page/page_body/__snapshots__/page_body.test.js.snap @@ -3,7 +3,33 @@ exports[`EuiPageBody is rendered 1`] = ` <div aria-label="aria-label" - class="euiPageBody euiPage--widthIsNotRestricted testClass1 testClass2" + class="euiPageBody testClass1 testClass2" + data-test-subj="test subject string" +/> +`; + +exports[`EuiPageBody restrict width can be set to a custom number 1`] = ` +<div + aria-label="aria-label" + class="euiPageBody euiPageBody--restrictWidth-custom testClass1 testClass2" + data-test-subj="test subject string" + style="max-width:1024px" +/> +`; + +exports[`EuiPageBody restrict width can be set to a custom value and measurement 1`] = ` +<div + aria-label="aria-label" + class="euiPageBody euiPageBody--restrictWidth-custom testClass1 testClass2" + data-test-subj="test subject string" + style="max-width:24rem" +/> +`; + +exports[`EuiPageBody restrict width can be set to a default 1`] = ` +<div + aria-label="aria-label" + class="euiPageBody euiPageBody--restrictWidth-default testClass1 testClass2" data-test-subj="test subject string" /> `; diff --git a/src/components/page/page_body/page_body.js b/src/components/page/page_body/page_body.js index 7c1ba034314..9d6b123506f 100644 --- a/src/components/page/page_body/page_body.js +++ b/src/components/page/page_body/page_body.js @@ -5,21 +5,14 @@ import classNames from 'classnames'; export const EuiPageBody = ({ children, restrictWidth, style, className, ...rest }) => { let widthClassname; + let newStyle; + if (restrictWidth === true) { - widthClassname = 'euiPage--restrictWidth-default'; - } else if (restrictWidth === false) { - widthClassname = 'euiPage--widthIsNotRestricted'; - } else { - widthClassname = 'euiPage--restrictWidth-custom'; - - // if style has been passed as a prop, add to it - if (style) { - style.maxWidth = `${restrictWidth}px`; - } - // otherwise create a new object - else { - style = { maxWidth: `${restrictWidth}px` }; - } + widthClassname = 'euiPageBody--restrictWidth-default'; + } else if (restrictWidth !== false) { + widthClassname = 'euiPageBody--restrictWidth-custom'; + const value = typeof maxWidth === 'number' ? `${restrictWidth}px` : restrictWidth; + newStyle = { ...style, maxWidth: value }; } const classes = classNames('euiPageBody', widthClassname, className); @@ -27,7 +20,7 @@ export const EuiPageBody = ({ children, restrictWidth, style, className, ...rest return ( <div className={classes} - style={style} + style={newStyle || style} {...rest} > {children} @@ -43,11 +36,13 @@ EuiPageBody.propTypes = { * Sets the max-width of the page, * set to `true` to use the default size, * set to `false` to not restrict the width, - * set to a number for a custom width. + * set to a number for a custom width in px, + * set to a string for a custom width in custom measurement. */ restrictWidth: PropTypes.oneOfType([ PropTypes.bool, - PropTypes.number + PropTypes.number, + PropTypes.string, ]), }; diff --git a/src/components/page/page_body/page_body.test.js b/src/components/page/page_body/page_body.test.js index f08a2d896bc..a455e3827e3 100644 --- a/src/components/page/page_body/page_body.test.js +++ b/src/components/page/page_body/page_body.test.js @@ -6,11 +6,28 @@ import { EuiPageBody } from './page_body'; describe('EuiPageBody', () => { test('is rendered', () => { - const component = render( - <EuiPageBody {...requiredProps} /> - ); + const component = render(<EuiPageBody {...requiredProps} />); - expect(component) - .toMatchSnapshot(); + expect(component).toMatchSnapshot(); + }); + + describe('restrict width', () => { + test('can be set to a default', () => { + const component = render(<EuiPageBody {...requiredProps} restrictWidth={true} />); + + expect(component).toMatchSnapshot(); + }); + + test('can be set to a custom number', () => { + const component = render(<EuiPageBody {...requiredProps} restrictWidth={1024} />); + + expect(component).toMatchSnapshot(); + }); + + test('can be set to a custom value and measurement', () => { + const component = render(<EuiPageBody {...requiredProps} restrictWidth="24rem" />); + + expect(component).toMatchSnapshot(); + }); }); });