Skip to content

Commit 3aacaf9

Browse files
chandlerprallConstancethompsongl
authored
[EuiPortal] convert to a function component, fix ssr bug (elastic#6055)
* convert EuiPortal to a function component, remove euiBody-hasPortalContent css class and usages * changelog * Revert "remove euiBody-hasPortalContent css class and usages" This reverts commit c841fae. * Refactor EuiPortal to a function component; added unit test around portalRef; updated EuiBottomBar tests to account for new portal lifecycle * Update upcoming_changelogs/6055.md Co-authored-by: Constance <constancecchen@users.noreply.github.com> * Added cypress tests for EuiPortal insertion logic * Update upcoming_changelogs/6055.md Co-authored-by: Greg Thompson <thompson.glowe@gmail.com> * Convert EuiWrappingPopover to a function component so changes to anchor are accounted for Co-authored-by: Constance <constancecchen@users.noreply.github.com> Co-authored-by: Greg Thompson <thompson.glowe@gmail.com>
1 parent 853cc04 commit 3aacaf9

8 files changed

Lines changed: 242 additions & 108 deletions

File tree

src/components/bottom_bar/__snapshots__/bottom_bar.test.tsx.snap

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Array [
66
aria-label="aria-label"
77
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingMedium testClass1 testClass2 emotion-euiBottomBar-fixed-m"
88
data-test-subj="test subject string"
9-
style="left:0;right:0;bottom:0"
9+
style="left: 0px; right: 0px; bottom: 0px;"
1010
>
1111
<h2
1212
class="emotion-euiScreenReaderOnly"
@@ -29,7 +29,7 @@ Array [
2929
<section
3030
aria-label="Page level controls"
3131
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingMedium emotion-euiBottomBar-fixed-m"
32-
style="left:0;right:0;bottom:0"
32+
style="left: 0px; right: 0px; bottom: 0px;"
3333
>
3434
<h2
3535
class="emotion-euiScreenReaderOnly"
@@ -65,7 +65,7 @@ Array [
6565
<section
6666
aria-label="This should have been label"
6767
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingMedium emotion-euiBottomBar-fixed-m"
68-
style="left:0;right:0;bottom:0"
68+
style="left: 0px; right: 0px; bottom: 0px;"
6969
>
7070
<h2
7171
class="emotion-euiScreenReaderOnly"
@@ -87,7 +87,7 @@ Array [
8787
<section
8888
aria-label="Page level controls"
8989
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingLarge emotion-euiBottomBar-fixed-l"
90-
style="left:0;right:0;bottom:0"
90+
style="left: 0px; right: 0px; bottom: 0px;"
9191
>
9292
<h2
9393
class="emotion-euiScreenReaderOnly"
@@ -109,7 +109,7 @@ Array [
109109
<section
110110
aria-label="Page level controls"
111111
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingMedium emotion-euiBottomBar-fixed-m"
112-
style="left:0;right:0;bottom:0"
112+
style="left: 0px; right: 0px; bottom: 0px;"
113113
>
114114
<h2
115115
class="emotion-euiScreenReaderOnly"
@@ -131,7 +131,7 @@ Array [
131131
<section
132132
aria-label="Page level controls"
133133
class="euiBottomBar euiBottomBar--fixed emotion-euiBottomBar-fixed"
134-
style="left:0;right:0;bottom:0"
134+
style="left: 0px; right: 0px; bottom: 0px;"
135135
>
136136
<h2
137137
class="emotion-euiScreenReaderOnly"
@@ -153,7 +153,7 @@ Array [
153153
<section
154154
aria-label="Page level controls"
155155
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingSmall emotion-euiBottomBar-fixed-s"
156-
style="left:0;right:0;bottom:0"
156+
style="left: 0px; right: 0px; bottom: 0px;"
157157
>
158158
<h2
159159
class="emotion-euiScreenReaderOnly"
@@ -175,7 +175,7 @@ Array [
175175
<section
176176
aria-label="Page level controls"
177177
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingMedium emotion-euiBottomBar-fixed-m"
178-
style="left:0;right:0;bottom:0"
178+
style="left: 0px; right: 0px; bottom: 0px;"
179179
>
180180
<h2
181181
class="emotion-euiScreenReaderOnly"
@@ -197,7 +197,7 @@ Array [
197197
<section
198198
aria-label="Page level controls"
199199
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingMedium emotion-euiBottomBar-fixed-m"
200-
style="left:30px;right:30px;bottom:30px;top:30px"
200+
style="left: 30px; right: 30px; bottom: 30px; top: 30px;"
201201
>
202202
<h2
203203
class="emotion-euiScreenReaderOnly"
@@ -219,7 +219,7 @@ Array [
219219
<section
220220
aria-label="Page level controls"
221221
class="euiBottomBar euiBottomBar--static euiBottomBar--paddingMedium emotion-euiBottomBar-static-m"
222-
style="left:0;right:0;bottom:0"
222+
style="left: 0px; right: 0px; bottom: 0px;"
223223
>
224224
<h2
225225
class="emotion-euiScreenReaderOnly"
@@ -241,7 +241,7 @@ Array [
241241
<section
242242
aria-label="Page level controls"
243243
class="euiBottomBar euiBottomBar--sticky euiBottomBar--paddingMedium emotion-euiBottomBar-sticky-m"
244-
style="left:0;right:0;bottom:0"
244+
style="left: 0px; right: 0px; bottom: 0px;"
245245
>
246246
<h2
247247
class="emotion-euiScreenReaderOnly"
@@ -263,7 +263,7 @@ Array [
263263
<section
264264
aria-label="Page level controls"
265265
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingMedium emotion-euiBottomBar-fixed-m"
266-
style="left:12px;right:0;bottom:0"
266+
style="left: 12px; right: 0px; bottom: 0px;"
267267
>
268268
<h2
269269
class="emotion-euiScreenReaderOnly"
@@ -285,7 +285,7 @@ Array [
285285
<section
286286
aria-label="Page level controls"
287287
class="euiBottomBar euiBottomBar--fixed euiBottomBar--paddingMedium emotion-euiBottomBar-fixed-m"
288-
style="left:0;right:0;bottom:0"
288+
style="left: 0px; right: 0px; bottom: 0px;"
289289
>
290290
<h2
291291
class="emotion-euiScreenReaderOnly"

src/components/bottom_bar/bottom_bar.test.tsx

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import React from 'react';
1010
import ReactDOM from 'react-dom';
11-
import { render, mount } from 'enzyme';
11+
import { mount } from 'enzyme';
1212
import { keysOf } from '../common';
1313
import { requiredProps, takeMountedSnapshot } from '../../test';
1414

@@ -28,52 +28,52 @@ ReactDOM.createPortal = (children) => {
2828

2929
describe('EuiBottomBar', () => {
3030
test('is rendered', () => {
31-
const component = render(
31+
const component = mount(
3232
<EuiBottomBar {...requiredProps}>Content</EuiBottomBar>
3333
);
3434

35-
expect(component).toMatchSnapshot();
35+
expect(component.render()).toMatchSnapshot();
3636
});
3737

3838
describe('props', () => {
3939
describe('paddingSize', () => {
4040
keysOf(paddingSizeToClassNameMap).forEach((paddingSize) => {
4141
test(`${paddingSize} is rendered`, () => {
42-
const component = render(<EuiBottomBar paddingSize={paddingSize} />);
42+
const component = mount(<EuiBottomBar paddingSize={paddingSize} />);
4343

44-
expect(component).toMatchSnapshot();
44+
expect(component.render()).toMatchSnapshot();
4545
});
4646
});
4747
});
4848

4949
describe('position', () => {
5050
POSITIONS.forEach((position) => {
5151
test(`${position} is rendered`, () => {
52-
const component = render(<EuiBottomBar position={position} />);
52+
const component = mount(<EuiBottomBar position={position} />);
5353

54-
expect(component).toMatchSnapshot();
54+
expect(component.render()).toMatchSnapshot();
5555
});
5656
});
5757
});
5858

5959
test('landmarkHeading', () => {
60-
const component = render(
60+
const component = mount(
6161
<EuiBottomBar landmarkHeading="This should have been label" />
6262
);
6363

64-
expect(component).toMatchSnapshot();
64+
expect(component.render()).toMatchSnapshot();
6565
});
6666

6767
test('affordForDisplacement can be false', () => {
68-
const component = render(<EuiBottomBar affordForDisplacement={false} />);
68+
const component = mount(<EuiBottomBar affordForDisplacement={false} />);
6969

70-
expect(component).toMatchSnapshot();
70+
expect(component.render()).toMatchSnapshot();
7171
});
7272

7373
test('usePortal can be false', () => {
74-
const component = render(<EuiBottomBar usePortal={false} />);
74+
const component = mount(<EuiBottomBar usePortal={false} />);
7575

76-
expect(component).toMatchSnapshot();
76+
expect(component.render()).toMatchSnapshot();
7777
});
7878

7979
test('bodyClassName is rendered', () => {
@@ -84,17 +84,17 @@ describe('EuiBottomBar', () => {
8484
});
8585

8686
test('style is customized', () => {
87-
const component = render(<EuiBottomBar style={{ left: 12 }} />);
87+
const component = mount(<EuiBottomBar style={{ left: 12 }} />);
8888

89-
expect(component).toMatchSnapshot();
89+
expect(component.render()).toMatchSnapshot();
9090
});
9191

9292
test('position props are altered', () => {
93-
const component = render(
93+
const component = mount(
9494
<EuiBottomBar top={30} right={30} bottom={30} left={30} />
9595
);
9696

97-
expect(component).toMatchSnapshot();
97+
expect(component.render()).toMatchSnapshot();
9898
});
9999
});
100100
});

src/components/popover/wrapping_popover.tsx

Lines changed: 31 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Side Public License, v 1.
77
*/
88

9-
import React, { Component } from 'react';
9+
import React, { FunctionComponent, useState, useEffect } from 'react';
1010
import { EuiPopover, Props as EuiPopoverProps } from './popover';
1111
import { EuiPortal } from '../portal';
1212

@@ -19,50 +19,36 @@ export interface EuiWrappingPopoverProps extends EuiPopoverProps {
1919
* then the button element is moved into the popover dom.
2020
* On unmount, the button is moved back to its original location.
2121
*/
22-
export class EuiWrappingPopover extends Component<EuiWrappingPopoverProps> {
23-
private portal: HTMLElement | null = null;
24-
private anchor: HTMLElement | null = null;
25-
26-
componentDidMount() {
27-
if (this.anchor) {
28-
this.anchor.insertAdjacentElement('beforebegin', this.props.button);
22+
export const EuiWrappingPopover: FunctionComponent<EuiWrappingPopoverProps> = ({
23+
button,
24+
...rest
25+
}) => {
26+
const [anchor, setAnchor] = useState<HTMLElement | null>(null);
27+
const [portal, setPortal] = useState<HTMLElement | null>(null);
28+
29+
useEffect(() => {
30+
if (anchor) {
31+
// move the button into the popover DOM
32+
anchor.insertAdjacentElement('beforebegin', button);
2933
}
30-
}
3134

32-
componentWillUnmount() {
33-
if (this.props.button.parentNode) {
34-
if (this.portal) {
35-
this.portal.insertAdjacentElement('beforebegin', this.props.button);
35+
return () => {
36+
if (portal) {
37+
// move the button back out of the popover DOM
38+
portal.insertAdjacentElement('beforebegin', button);
3639
}
37-
}
38-
}
39-
40-
setPortalRef = (node: HTMLElement | null) => {
41-
this.portal = node;
42-
};
43-
44-
setAnchorRef = (node: HTMLElement | null) => {
45-
this.anchor = node;
46-
};
47-
48-
render() {
49-
const { button, ...rest } = this.props;
50-
51-
return (
52-
<EuiPortal
53-
portalRef={this.setPortalRef}
54-
insert={{ sibling: this.props.button, position: 'after' }}
55-
>
56-
<EuiPopover
57-
{...rest}
58-
button={
59-
<div
60-
ref={this.setAnchorRef}
61-
className="euiWrappingPopover__anchor"
62-
/>
63-
}
64-
/>
65-
</EuiPortal>
66-
);
67-
}
68-
}
40+
};
41+
}, [anchor, button, portal]);
42+
43+
return (
44+
<EuiPortal
45+
portalRef={setPortal}
46+
insert={{ sibling: button, position: 'after' }}
47+
>
48+
<EuiPopover
49+
{...rest}
50+
button={<div ref={setAnchor} className="euiWrappingPopover__anchor" />}
51+
/>
52+
</EuiPortal>
53+
);
54+
};

src/components/portal/__snapshots__/portal.test.tsx.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ exports[`EuiPortal is rendered 1`] = `
55
<EuiPortal>
66
<Portal
77
containerInfo={
8-
<div>
8+
<div
9+
data-euiportal="true"
10+
>
911
Content
1012
</div>
1113
}

0 commit comments

Comments
 (0)