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; };