I've got a React/Material UI app. The Portal displays a Panel and a Widget.
Main App: Display Portal and Set Background to Blue
export default function App() {
return (
<div
style={{
backgroundColor: "blue"
}}
>
<Portal></Portal>
</div>
);
}
Here is my codesandbox.
The key files to look at are Portal.js, and Layout.js.
Layout defines parameters to be applied at each breakpoint. It is intended to aid in the design of the Portal responsiveness to window size.
Portal places the Widget at the upper left, and dynamically "flexes" the Panel to fall beneath the widget at "xs", and "sm", and to the right of the widget at "md", "lg", and "xl".
The Widget retains its aspect ratio. In the following example, the Widget has a width of 400 and a height of 800. However this can change based on user action.
Portal has two primary methods, the React functional component, and the Material UI makeStyles function.
Portal: React Functional Component
export default function Portal() {
const selWidHeight = 400;
const selWidWidth = 800;
const layout = Layout(selWidHeight / selWidWidth);
const sizes = {
containerWidth: layout.selWidgetWidth,
containerHeight: layout.selWidgetHeight,
bookmarkPanelContainerHeight: "600px",
widgetWidth: "90%",
widgetHeight: "90%",
viewWidth: layout.viewWidth
};
const classes = useStyles(sizes);
return (
<>
<>
{layout.viewWidth > 0 ? (
<Grid
container
direction="row"
alignItems="flex-start"
alignContent="flex-start"
className={classes.root}
>
<Grid
item
xs={layout.xs.widgetGridCells}
sm={layout.sm.widgetGridCells}
md={layout.md.widgetGridCells}
lg={layout.lg.widgetGridCells}
xl={layout.xl.widgetGridCells}
>
<Container
className={classes.widgetContainer}
disableGutters={true}
maxWidth={false}
>
<Widget
className={classes.widget}
width={sizes.widgetWidth}
height={sizes.widgetHeight}
/>
</Container>
</Grid>
<Grid
item
xs={layout.xs.bmkGridCells}
sm={layout.sm.bmkGridCells}
md={layout.md.bmkGridCells}
lg={layout.lg.bmkGridCells}
xl={layout.xl.bmkGridCells}
>
<Container
className={classes.bookmarkPanel}
disableGutters={true}
>
<Panel />
</Container>
</Grid>
</Grid>
) : (
<div>Window Too Small</div>
)}
</>
</>
);
}
Portal: makeStyles Function
const useStyles = makeStyles((theme) => {
return {
root: {
width: (props) => props.viewWidth,
height: "100%",
margin: "0px"
},
rootContainer: {
display: "flex",
justifyContent: "flex-start",
flexDirection: "row"
},
widgetContainer: {
width: (props) => props.containerWidth,
height: (props) => props.containerHeight,
minWidth: (props) => props.containerWidth,
backgroundColor: "orange",
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "center",
alignItems: "center",
position: "relative"
},
bookmarkPanel: {
overflowY: "scroll",
border: "1px solid green",
float: "left",
height: (props) => props.bookmarkPanelContainerHeight,
position: "relative",
background: "repeating-linear-gradient(17deg, #ebf8e1 15%, #f69d3c 20%)"
},
widget: {
width: (props) => {
return props.containerWidth;
},
height: (props) => {
return props.widgetHeight;
},
background:
"repeating-linear-gradient(45deg, #3f87a6, #ebf8e1 15%, #f69d3c 20%)",
position: "absolute"
}
};
});
Panel: Styled Div
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "red"
}
}));
const Panel = () => {
const classes = useStyles();
return <div className={classes.root}>Panel </div>;
};
Widget: Styled Div of a Given Width and Height - Aspect Ratio is Important
const useStyles = makeStyles((theme) => ({
root: {
width: (props) => props.width,
height: (props) => props.height,
background:
"repeating-linear-gradient(45deg, #3f87a6, #ebf8e1 15%, #f69d3c 20%)"
}
}));
const Widget = ({ width, height }) => {
const props = { width: width, height: height };
const classes = useStyles(props);
return <div className={classes.root}>Widget </div>;
};
Layout Controls Key Parameters:
const Layout = (aspect_ratio) => {
const theme = useTheme();
const xsMatches = useMediaQuery(theme.breakpoints.up("xs"));
const smMatches = useMediaQuery(theme.breakpoints.up("sm"));
const mdMatches = useMediaQuery(theme.breakpoints.up("md"));
const lgMatches = useMediaQuery(theme.breakpoints.up("lg"));
const xlMatches = useMediaQuery(theme.breakpoints.up("xl"));
var sizingDetails = {
xl: {
widgetGridCells: 10,
bmkGridCells: 2
},
lg: {
widgetGridCells: 8,
bmkGridCells: 4
},
md: {
widgetGridCells: 9,
bmkGridCells: 3
},
sm: {
widgetGridCells: 12,
bmkGridCells: 12
},
xs: {
widgetGridCells: 12,
bmkGridCells: 12
}
};
if (xlMatches) {
sizingDetails.selWidgetWidth = (theme.breakpoints.values.xl * 10.0) / 12.0;
sizingDetails.viewWidth = theme.breakpoints.values.xl;
console.log("xl: ", sizingDetails);
} else if (lgMatches) {
sizingDetails.selWidgetWidth = (theme.breakpoints.values.lg * 8.0) / 12.0;
sizingDetails.viewWidth = theme.breakpoints.values.lg;
console.log("lg: ", sizingDetails);
} else if (mdMatches) {
sizingDetails.selWidgetWidth = (theme.breakpoints.values.md * 9) / 12.0;
sizingDetails.viewWidth = theme.breakpoints.values.md;
console.log("md: ", sizingDetails);
} else if (smMatches) {
sizingDetails.selWidgetWidth = theme.breakpoints.values.sm;
sizingDetails.viewWidth = theme.breakpoints.values.sm;
console.log("sm: ", sizingDetails);
} else if (xsMatches) {
sizingDetails.selWidgetWidth = theme.breakpoints.values.xs;
sizingDetails.viewWidth = theme.breakpoints.values.xs;
console.log("xs: ", sizingDetails);
} else {
sizingDetails.selWidgetWidth = 0;
sizingDetails.viewWidth = 0;
console.log("none: ", sizingDetails);
}
sizingDetails.selWidgetHeight = sizingDetails.selWidgetWidth * aspect_ratio;
return sizingDetails;
};
export default Layout;
I am building this to be responsive to the size of the containing window (shown blue below). My current issue is with "md", "lg", and "xl" breakpoints.
I am currently ok with "sm", and "xs" (in that case the Panel is displayed below the Widget, and its width is not an issue for me.).
At medium, large and extra large I want to display the Panel to the right as you see here (for medium - md):
In this view the Widget is displayed properly. The Panel is in the correct location, with the correct height. However I want its width to "right-fill" the blue containing window at this breakpoint, and it does not.
In short, the Panel's width should expand dynamically (as the browser window's width is increased in size, for a given breakpoint) to fill the blue containing div.
The styling on the Panel div shows that it is a fixed 240 pixels wide at this breakpoint. This 240 must be changed dynamically to ensure that the div increases to fill the container.
The styling on the Grid container:
In response to prior feedback, I've reduced this experiment to the smallest possible code footprint, and have captured that in codesandbox
Here is my codesandbox.