diff --git a/CHANGELOG.md b/CHANGELOG.md index 9afad41135a..dd386e88cfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Bug fixes** - Fixed invalid color entry passed to `EuiBadge` color prop ([#4481](https://github.com/elastic/eui/pull/4481)) +- Fixed `EuiCodeBlock` focus-state if content overflows ([#4463]https://github.com/elastic/eui/pull/4463) ## [`31.5.0`](https://github.com/elastic/eui/tree/v31.5.0) diff --git a/src/components/code/__snapshots__/_code_block.test.tsx.snap b/src/components/code/__snapshots__/_code_block.test.tsx.snap index e639fafbf7f..d2369076574 100644 --- a/src/components/code/__snapshots__/_code_block.test.tsx.snap +++ b/src/components/code/__snapshots__/_code_block.test.tsx.snap @@ -6,6 +6,7 @@ exports[`EuiCodeBlockImpl block highlights javascript code, adding "js" class 1` >
-
+
constvalue =
'State 1'
@@ -16,7 +16,7 @@ exports[`EuiCodeBlock dynamic content updates DOM when input changes 1`] = `
exports[`EuiCodeBlock dynamic content updates DOM when input changes 2`] = `
"
-
+
constvalue =
'State 2'
@@ -32,6 +32,7 @@ exports[`EuiCodeBlock props fontSize l is rendered 1`] = `
>
= ({
const [isPortalTargetReady, setIsPortalTargetReady] = useState(false);
const codeTarget = useRef(null);
const code = useRef(null);
+ const [wrapperRef, setWrapperRef] = useState(null);
+ const [innerTextRef, innerText] = useInnerText('');
+ const [tabIndex, setTabIndex] = useState<-1 | 0>(-1);
+ const combinedRef = useCombinedRefs([
+ innerTextRef,
+ setWrapperRef,
+ ]);
+ const { width, height } = useResizeObserver(wrapperRef);
const [codeFullScreen, setCodeFullScreen] = useState(
null
);
+ const doesOverflow = () => {
+ if (!wrapperRef) return;
+
+ const { clientWidth, clientHeight, scrollWidth, scrollHeight } = wrapperRef;
+ const doesOverflow =
+ scrollHeight > clientHeight || scrollWidth > clientWidth;
+
+ setTabIndex(doesOverflow ? 0 : -1);
+ };
+
+ useMutationObserver(wrapperRef, doesOverflow, {
+ subtree: true,
+ childList: true,
+ });
+
+ useEffect(doesOverflow, [width, height, wrapperRef]);
+
useEffect(() => {
codeTarget.current = document.createElement('div');
setIsPortalTargetReady(true);
@@ -292,11 +314,10 @@ export const EuiCodeBlockImpl: FunctionComponent = ({
-
+
@@ -311,31 +332,26 @@ export const EuiCodeBlockImpl: FunctionComponent = ({
return fullScreenDisplay;
};
+ const codeBlockControls = getCodeBlockControls(innerText);
return isPortalTargetReady ? (
<>
{createPortal(children, codeTarget.current!)}
-
- {(innerTextRef, innerText) => {
- const codeBlockControls = getCodeBlockControls(innerText);
- return (
-
-
- {codeSnippet}
-
-
- {/*
- If the below fullScreen code renders, it actually attaches to the body because of
- EuiOverlayMask's React portal usage.
- */}
- {codeBlockControls}
- {getFullScreenDisplay(codeBlockControls)}
-
- );
- }}
-
+
+
+ {codeSnippet}
+
+
+ {/*
+ If the below fullScreen code renders, it actually attaches to the body because of
+ EuiOverlayMask's React portal usage.
+ */}
+ {codeBlockControls}
+ {getFullScreenDisplay(codeBlockControls)}
+
>
) : null;
};