Skip to content

Commit

Permalink
EuiBottomBar: allow customization of whether the component makes room…
Browse files Browse the repository at this point in the history
… for itself (#4156)
  • Loading branch information
cchaos authored Oct 27, 2020
1 parent 7857f26 commit ff65405
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- Improved `EuiButtonGroup` focus, hover, selected and disabled states ([#4142](https://github.com/elastic/eui/pull/4142))
- Added `display` prop to `EuiToolTip` for common display block needs ([#4148](https://github.com/elastic/eui/pull/4148))
- Added support for more colors in `EuiProgress` such as `vis0` through `vis9`, `warning`, `success` and custom colors ([#4130](https://github.com/elastic/eui/pull/4130))
- Added `affordForDisplacement` prop to `EuiBottomBar` ([#4156](https://github.com/elastic/eui/pull/4156))

**Bug fixes**

Expand Down
2 changes: 1 addition & 1 deletion src-docs/src/views/bottom_bar/bottom_bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default () => {
const [showBar, setShowBar] = useState(false);

const button = (
<EuiButton color="primary" onClick={() => setShowBar(!showBar)}>
<EuiButton color="primary" onClick={() => setShowBar((show) => !show)}>
Toggle appearance of the bottom bar
</EuiButton>
);
Expand Down
58 changes: 58 additions & 0 deletions src-docs/src/views/bottom_bar/bottom_bar_displacement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { useState } from 'react';

import {
EuiBottomBar,
EuiButtonGroup,
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
} from '../../../../src/components';

export default () => {
const [toggleIdSelected, setToggleIdSelected] = useState(null);

const toggleButtons = [
{
id: 'bottomBarStandard',
label: 'Show bottom bar',
},
{
id: 'bottomBarWithoutAffordForDisplacement',
label: 'Show bottom bar (without affordForDisplacement behavior)',
},
];

const onChange = (optionId) => {
setToggleIdSelected(optionId);
};

return (
<div>
<EuiButtonGroup
legend="Bottom Bar demo toggle buttons group"
type="single"
buttonSize="m"
options={toggleButtons}
idSelected={toggleIdSelected}
onChange={(id) => onChange(id)}
/>

{toggleIdSelected && (
<EuiBottomBar
affordForDisplacement={toggleIdSelected === 'bottomBarStandard'}>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty
onClick={() => setToggleIdSelected(null)}
color="ghost"
size="s"
iconType="cross">
close
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiBottomBar>
)}
</div>
);
};
42 changes: 39 additions & 3 deletions src-docs/src/views/bottom_bar/bottom_bar_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ const bottomBarSnippet = `<EuiBottomBar paddingSize="s">
<!-- Content goes here -->
</EuiBottomBar>`;

import BottomBarDisplacement from './bottom_bar_displacement';
const bottomBarDisplacementSource = require('!!raw-loader!./bottom_bar_displacement');
const bottomBarDisplacementHtml = renderToHtml(BottomBarDisplacement);

const bottomBarDisplacementSnippet = `<EuiBottomBar affordForDisplacement={false}>
<!-- Content goes here -->
</EuiBottomBar>`;

export const BottomBarExample = {
title: 'Bottom bar',
sections: [
Expand All @@ -29,7 +37,7 @@ export const BottomBarExample = {
},
],
text: (
<div>
<>
<p>
<strong>EuiBottomBar</strong> is a simple wrapper component that
does nothing but fix a bottom bar (usually filled with buttons) to
Expand All @@ -41,13 +49,41 @@ export const BottomBarExample = {
Like many of our other wrapper components,{' '}
<strong>EuiBottomBar</strong> accepts a{' '}
<EuiCode>paddingSize</EuiCode> prop, which can be set to{' '}
<EuiCode>s / m / l / none</EuiCode>.
<EuiCode>s / m (default) / l / none</EuiCode>.
</p>
</div>
</>
),
props: { EuiBottomBar },
snippet: bottomBarSnippet,
demo: <BottomBar />,
},
{
title: 'Displacement',
source: [
{
type: GuideSectionTypes.JS,
code: bottomBarDisplacementSource,
},
{
type: GuideSectionTypes.HTML,
code: bottomBarDisplacementHtml,
},
],
text: (
<>
<p>
There is an <EuiCode>affordForDisplacement</EuiCode> prop
(defaulting to <EuiCode>true</EuiCode>), which determines whether
the component makes room for itself by adding bottom padding
equivalent to its own height on the document body element. Setting
this to <EuiCode>false</EuiCode> can be useful to minimize scrollbar
visibility but will cause the bottom bar to overlap body content.
</p>
</>
),
props: { EuiBottomBar },
snippet: bottomBarDisplacementSnippet,
demo: <BottomBarDisplacement />,
},
],
};
34 changes: 34 additions & 0 deletions src/components/bottom_bar/__snapshots__/bottom_bar.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,40 @@ Array [
]
`;

exports[`EuiBottomBar props affordForDisplacement can be false 1`] = `
Array [
<section
aria-label="Page level controls"
class="euiBottomBar euiBottomBar--paddingMedium"
>
<h2
class="euiScreenReaderOnly"
>
Page level controls
</h2>
</section>,
<p
aria-live="assertive"
class="euiScreenReaderOnly"
>
There is a new region landmark with page level controls at the end of the document.
</p>,
]
`;

exports[`EuiBottomBar props bodyClassName is rendered 1`] = `
<section
aria-label="Page level controls"
class="euiBottomBar euiBottomBar--paddingMedium"
>
<h2
class="euiScreenReaderOnly"
>
Page level controls
</h2>
</section>
`;

exports[`EuiBottomBar props paddingSize l is rendered 1`] = `
Array [
<section
Expand Down
23 changes: 20 additions & 3 deletions src/components/bottom_bar/bottom_bar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@

import React from 'react';
import ReactDOM from 'react-dom';
import { render } from 'enzyme';
import { requiredProps } from '../../test/required_props';
import { render, mount } from 'enzyme';
import { keysOf } from '../common';
import { requiredProps, takeMountedSnapshot } from '../../test';

import { EuiBottomBar, paddingSizeToClassNameMap } from './bottom_bar';

// @ts-ignore TODO: Temporary hack which we can remove once react-test-renderer supports portals.
// More info at https://github.com/facebook/react/issues/11565.
ReactDOM.createPortal = (node) => node;
ReactDOM.createPortal = (children) => {
// hack to make enzyme treat the portal as a fragment
if (children == null) return [['nested']];
return children;
};

describe('EuiBottomBar', () => {
test('is rendered', () => {
Expand All @@ -48,5 +52,18 @@ describe('EuiBottomBar', () => {
});
});
});

test('affordForDisplacement can be false', () => {
const component = render(<EuiBottomBar affordForDisplacement={false} />);

expect(component).toMatchSnapshot();
});

test('bodyClassName is rendered', () => {
const component = mount(<EuiBottomBar bodyClassName={'customClass'} />);

expect(takeMountedSnapshot(component)).toMatchSnapshot();
expect(document.body.classList.contains('customClass')).toBe(true);
});
});
});
58 changes: 49 additions & 9 deletions src/components/bottom_bar/bottom_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,34 +38,73 @@ export const paddingSizeToClassNameMap: {

interface Props extends CommonProps {
/**
* Optional class applied to the body class
* Padding applied to the bar. Default is 'm'.
*/
bodyClassName?: string;
paddingSize: BottomBarPaddingSize;

/**
* Whether the component should apply padding on the document body element to afford for its own displacement height.
* Default is true.
*/
affordForDisplacement: boolean;

/**
* Padding applied to the bar
* Optional class applied to the body element on mount
*/
paddingSize?: BottomBarPaddingSize;
bodyClassName?: string;

/**
* Customize the screen reader heading that helps users find this control. Default is "Page level controls".
* Customize the screen reader heading that helps users find this control. Default is 'Page level controls'.
*/
landmarkHeading?: string;
}

export class EuiBottomBar extends Component<Props> {
static defaultProps = {
paddingSize: 'm',
affordForDisplacement: true,
};

private bar: HTMLElement | null = null;

componentDidMount() {
const height = this.bar ? this.bar.clientHeight : -1;
document.body.style.paddingBottom = `${height}px`;
if (this.props.affordForDisplacement) {
const height = this.bar ? this.bar.clientHeight : -1;
document.body.style.paddingBottom = `${height}px`;
}

if (this.props.bodyClassName) {
document.body.classList.add(this.props.bodyClassName);
}
}

componentDidUpdate(prevProps: Props) {
if (prevProps.affordForDisplacement !== this.props.affordForDisplacement) {
if (this.props.affordForDisplacement) {
// start affording for displacement
const height = this.bar ? this.bar.clientHeight : -1;
document.body.style.paddingBottom = `${height}px`;
} else {
// stop affording for displacement
document.body.style.paddingBottom = '';
}
}

if (prevProps.bodyClassName !== this.props.bodyClassName) {
if (prevProps.bodyClassName) {
document.body.classList.remove(prevProps.bodyClassName);
}
if (this.props.bodyClassName) {
document.body.classList.add(this.props.bodyClassName);
}
}
}

componentWillUnmount() {
document.body.style.paddingBottom = '';
if (this.props.affordForDisplacement) {
document.body.style.paddingBottom = '';
}

if (this.props.bodyClassName) {
document.body.classList.remove(this.props.bodyClassName);
}
Expand All @@ -75,9 +114,10 @@ export class EuiBottomBar extends Component<Props> {
const {
children,
className,
paddingSize = 'm',
paddingSize,
bodyClassName,
landmarkHeading,
affordForDisplacement,
...rest
} = this.props;

Expand Down

0 comments on commit ff65405

Please sign in to comment.