Skip to content

Commit 3efa7c9

Browse files
fix(EuiCodeBlock): fixes re-renders causing blank lines to appear when using isVirtualized if scrolled (#9196)
Co-authored-by: Lene Gadewoll <[email protected]>
1 parent b813185 commit 3efa7c9

File tree

5 files changed

+118
-14
lines changed

5 files changed

+118
-14
lines changed
107 KB
Loading
67.6 KB
Loading
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
**Bug fixes**
2+
3+
- Fixed virtualized `EuiCodeBlock` rendering blank lines when content updates if scrolled.

packages/eui/src/components/code/code_block.stories.tsx

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@
66
* Side Public License, v 1.
77
*/
88

9-
import React from 'react';
9+
import React, { useEffect, useState } from 'react';
1010
import type { Meta, StoryObj, ReactRenderer } from '@storybook/react';
1111
import type { PlayFunctionContext } from '@storybook/csf';
12+
import { css } from '@emotion/react';
1213

1314
import { within } from '../../../.storybook/test';
1415
import { LOKI_SELECTORS } from '../../../.storybook/loki';
16+
import { mathWithUnits } from '../../global_styling';
1517

1618
import { EuiCodeBlock, EuiCodeBlockProps } from './code_block';
1719
import { expect, userEvent } from '@storybook/test';
20+
import { EuiButton } from '../button';
21+
import { EuiFlexGroup, EuiFlexItem } from '../flex';
1822

1923
const meta: Meta<EuiCodeBlockProps> = {
2024
title: 'Editors & Syntax/EuiCodeBlock',
@@ -148,3 +152,97 @@ export const HighContrast: Story = {
148152
],`,
149153
},
150154
};
155+
156+
/* This Story verifies that updated data in a virtualized code block is
157+
rendered correctly and not cut-off after scrolling */
158+
export const VirtualizedCodeBlockScrolling: Story = {
159+
tags: ['vrt-only'],
160+
parameters: {
161+
loki: {
162+
chromeSelector: LOKI_SELECTORS.portal,
163+
},
164+
codeSnippet: {
165+
skip: true,
166+
},
167+
},
168+
// use dark mode to better visualize container boundaries
169+
globals: { colorMode: 'dark' },
170+
render: function Render() {
171+
const [response, setResponse] = useState('{}');
172+
const [isLoading, setIsLoading] = useState(false);
173+
174+
const handleSubmit = async () => {
175+
setIsLoading(true);
176+
177+
try {
178+
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
179+
const data = await res.json();
180+
181+
setResponse(JSON.stringify(data, null, 2));
182+
} catch (error) {
183+
console.error(error);
184+
} finally {
185+
// delay to keep VRT images more stable
186+
setTimeout(() => {
187+
setIsLoading(false);
188+
});
189+
}
190+
};
191+
192+
useEffect(() => {
193+
handleSubmit();
194+
}, []);
195+
196+
useEffect(() => {
197+
// scroll the code block after response updates to test if virtualization
198+
// calculates the scroll height and position correctly
199+
const pre = document.querySelector('.euiCodeBlock__pre');
200+
if (pre) {
201+
pre.scrollBy({
202+
top: 75,
203+
});
204+
205+
// trigger a second load after scroll to simulate potential issues
206+
setTimeout(() => {
207+
handleSubmit();
208+
}, 10);
209+
}
210+
}, [response]);
211+
212+
return (
213+
<EuiFlexGroup
214+
direction="row"
215+
gutterSize="m"
216+
css={({ euiTheme }) => css`
217+
block-size: calc(
218+
100vh - ${mathWithUnits(euiTheme.size.base, (x) => x * 2)}
219+
);
220+
`}
221+
>
222+
<EuiFlexItem grow={false}>
223+
<EuiButton
224+
type="submit"
225+
iconType="sortRight"
226+
isLoading={isLoading}
227+
onClick={handleSubmit}
228+
>
229+
Submit
230+
</EuiButton>
231+
</EuiFlexItem>
232+
<EuiFlexItem grow={2}>
233+
<EuiCodeBlock
234+
language="json"
235+
fontSize="s"
236+
paddingSize="m"
237+
isCopyable={true}
238+
lineNumbers
239+
isVirtualized
240+
overflowHeight="100%"
241+
>
242+
{response}
243+
</EuiCodeBlock>
244+
</EuiFlexItem>
245+
</EuiFlexGroup>
246+
);
247+
},
248+
};

packages/eui/src/components/code/code_block_virtualized.tsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,31 @@ export const EuiCodeBlockVirtualized = ({
3232
preProps: HTMLAttributes<HTMLPreElement>;
3333
codeProps: HTMLAttributes<HTMLElement>;
3434
}) => {
35+
// NOTE: Don't inject other content (e.g. a label) inside this outer virtualized
36+
// container as react-window requires this to be stable for scroll calculations.
37+
// Instead, inject it into the inner virtualized element.
3538
const VirtualizedOuterElement = useMemo(
3639
() =>
37-
forwardRef<any, any>(({ style, children, ...props }, ref) => (
38-
<pre style={logicalStyles(style)} {...props} ref={ref} {...preProps}>
39-
{label}
40-
{children}
41-
</pre>
40+
forwardRef<any, any>(({ style, ...props }, ref) => (
41+
<pre style={logicalStyles(style)} {...props} ref={ref} {...preProps} />
4242
)),
43-
[preProps, label]
43+
[preProps]
4444
);
4545

4646
const VirtualizedInnerElement = useMemo(
4747
() =>
4848
forwardRef<any, any>(({ style, ...props }, ref) => (
49-
<code
50-
style={logicalStyles(style)}
51-
{...props}
52-
ref={ref}
53-
{...codeProps}
54-
/>
49+
<>
50+
{label}
51+
<code
52+
style={logicalStyles(style)}
53+
{...props}
54+
ref={ref}
55+
{...codeProps}
56+
/>
57+
</>
5558
)),
56-
[codeProps]
59+
[codeProps, label]
5760
);
5861

5962
const virtualizationProps = {

0 commit comments

Comments
 (0)