Repository: Sage/carbon (ts)

Issue:
inputs overlap fixed positions
### Current behaviour

All kind of inputs (radio buttons, textbox, select...) overlap a box with the `position: sticky` rule, as they have a z-index of 999, while the box doesn't have a custom z-index.

<img width="367" alt="image" src="https://user-images.githubusercontent.com/38105312/196965157-6cc1ca06-eb55-40c0-8cb8-aec6bf480a00.png">


### Expected behaviour

For the inputs to go under the sticky box, as the rest of the text.

### CodeSandbox or Storybook URL

https://codesandbox.io/s/sidebar-with-sticky-content-forked-xgyefg?file=/src/index.js

### JIRA Ticket (Sage Only)

SBS-44457

### Suggested Solution

_No response_

### Carbon Version

111.4.2

### Design Tokens Version

_No response_

### What browsers are you seeing the problem on?

Chrome

### What Operating System are you seeing the problem on?

MacOS

### Anything else we should know?

_No response_

### Confidentiality

- [X] I confirm there is no confidential or commercially sensitive information included.

Pull request description:
fix(box): ensure z-index is set when sticky or fixed positioned
fix #5572

### Proposed behaviour

<!--
A clear and concise description of what changes this PR makes.

If applicable, add screenshots of a codesandbox to help explain your request. You can paste these directly into GitHub.

Please DO NOT share screenshots or the source code of your project.

You can create a codesandbox to show the behaviour before/after this pull request by forking this template https://codesandbox.io/s/carbon-quickstart-j5pb2

If you include a CodeSandbox link, the bot will fork it with the new built version of carbon.
If you have a commit that includes fixes #XXXX and issue #XXXX has a CodeSandbox link in the body, the bot will fork
it with the new built version of carbon.
-->
Ensures that the any `Box` container that has `sticky` or `fixed` positioning has a z-index set to prevent it being overlaid by other elements that are relatively positioned

### Current behaviour

<!--
A clear and concise description of the behaviour before this change.

If applicable, add screenshots. You can paste these directly into GitHub.
-->
Any `Box` container that has `sticky` or `fixed` positioning has no z-index set

### Checklist

<!-- Each PR should include the following -->

- [x] Commits follow our style guide
- [x] Related issues linked in commit messages if required
- [x] Unit tests added or updated if required
- [x] Cypress automation tests added or updated if required

#### QA

- [ ] Tested in CodeSandbox/storybook
- [ ] Add new Cypress test coverage if required
- [ ] Carbon implementation matches Design System/designs
- [ ] UI Tests GitHub check reviewed if required

### Additional context

<!-- Add any other context or links about the pull request here. -->

### Testing instructions

<!-- How can a reviewer test this PR? -->
See sandbox in linked issue below

The following CodeSandbox is an example of the broken behaviour.
You can see the new behaviour by looking at the version in the comment by `codesandbox[bot]`.

<!-- Add CodeSandbox here -->


Patch:
diff --git a/src/components/box/box.component.tsx b/src/components/box/box.component.tsx
index 26463eff6..f8af112c3 100644
--- a/src/components/box/box.component.tsx
+++ b/src/components/box/box.component.tsx
@@ -8,7 +8,7 @@ import {
   flexbox,
   FlexboxProps,
   ColorProps,
-  position,
+  position as positionFn,
   PositionProps,
 } from "styled-system";
 import * as DesignTokens from "@sage/design-tokens/js/base/common";
@@ -56,6 +56,16 @@ export interface BoxProps
 
 let isDeprecationWarningTriggered = false;
 
+const calculatePosition = (props: Omit<PositionProps, "zIndex">) => {
+  const { position, ...rest } = positionFn(props);
+
+  return {
+    position,
+    zIndex: ["sticky", "fixed"].includes(position) ? 1 : undefined,
+    ...rest,
+  };
+};
+
 export const Box = styled.div<BoxProps>`
   ${() => {
     if (!isDeprecationWarningTriggered) {
@@ -70,7 +80,7 @@ export const Box = styled.div<BoxProps>`
   ${space}
   ${layout}
   ${flexbox}
-  ${position}
+  ${calculatePosition}
 
   ${({ color, bg, backgroundColor, ...rest }) =>
     styledColor({ color, bg, backgroundColor, ...rest })}
diff --git a/src/components/box/box.spec.tsx b/src/components/box/box.spec.tsx
index 6dfef688b..4a996207d 100644
--- a/src/components/box/box.spec.tsx
+++ b/src/components/box/box.spec.tsx
@@ -14,6 +14,7 @@ import Box, {
   BoxSizing,
   AllowedNumericalValues,
   Gap,
+  BoxProps,
 } from "./box.component";
 import boxConfig from "./box.config";
 
@@ -119,4 +120,30 @@ describe("Box", () => {
       wrapper
     );
   });
+
+  it.each<BoxProps["position"]>(["fixed", "sticky"])(
+    "sets zIndex to 1 when position is %s",
+    (position) => {
+      const wrapper = mount(<Box position={position} />);
+      assertStyleMatch(
+        {
+          zIndex: "1",
+        },
+        wrapper
+      );
+    }
+  );
+
+  it.each<BoxProps["position"]>(["absolute", "relative"])(
+    "does not set zIndex when position is %s",
+    (position) => {
+      const wrapper = mount(<Box position={position} />);
+      assertStyleMatch(
+        {
+          zIndex: undefined,
+        },
+        wrapper
+      );
+    }
+  );
 });


Test patch:
diff --git a/src/components/box/box.test.js b/src/components/box/box.test.js
index 09bad28ed..eea744d16 100644
--- a/src/components/box/box.test.js
+++ b/src/components/box/box.test.js
@@ -3,6 +3,8 @@ import Box from "./box.component";
 import CypressMountWithProviders from "../../../cypress/support/component-helper/cypress-mount";
 import { getDataElementByValue } from "../../../cypress/locators";
 import { useJQueryCssValueAndAssert } from "../../../cypress/support/component-helper/common-steps";
+import RadioButton, { RadioButtonGroup } from "../radio-button";
+import { radiobuttonComponent } from "../../../cypress/locators/radiobutton";
 
 const colorConstants = [
   ["red", "rgb(255, 0, 0)", "#FF0000"],
@@ -107,6 +109,24 @@ const verifyScrollbarVariant = (variant, thumbColor, trackColor) =>
     expect(colorValueTrack).to.eq(trackColor);
   });
 
+const BoxComponentSticky = () => {
+  return (
+    <Box data-element="scrollable-box" height="95vh" overflowY="auto">
+      <Box position="sticky" top="0px" height="100px" bg="black">
+        foo
+      </Box>
+      <Box>
+        <Box height="100px">Foo</Box>
+        <RadioButtonGroup inline legend="test" name="test-group">
+          <RadioButton id="test-1" value="1" label="first" size="large" />
+          <RadioButton id="test-2" value="2" label="second" size="large" />
+        </RadioButtonGroup>
+        <Box height="110vh">Foo</Box>
+      </Box>
+    </Box>
+  );
+};
+
 context("Testing Box component", () => {
   describe("should render Box component", () => {
     it.each(colorConstants)(
@@ -843,5 +863,13 @@ context("Testing Box component", () => {
         "rgba(0, 20, 30, 0.04) 0px 10px 40px 0px, rgba(0, 20, 30, 0.1) 0px 50px 80px 0px"
       );
     });
+
+    it("should not render inputs over a Box with position sticky", () => {
+      cy.viewport(900, 200);
+      CypressMountWithProviders(<BoxComponentSticky />);
+
+      getDataElementByValue("scrollable-box").scrollTo(0, 300);
+      radiobuttonComponent().should("not.be.visible");
+    });
   });
 });