Material-UI NextJS Button Styling Issue - html

i am having a problem getting the styling right on a couple of buttons in JS, it seems when i add a styling class via className that on first render the formatting works, but on subsequent refreshes it loses its styling. It is only happening on the two individual buttons i have. After troubleshooting for ages, i have found that everything works when i use SX instead of classNames, so if i do this then the refresh works. So in code below one button styles and remains styles, but the second one, refreshing my button class does not? Stumped at this point, i ran through forums and see a lot about NextJs needing some extra config in _document and _app to make it work, but i ran this in from the NextJs Material UI boiler plate from Git so dont think it could be that causing it.
Code:
import React from 'react'
import { AppBar, Toolbar, alpha } from "#mui/material";
import Button from '#mui/material/Button'
import ButtonBase from '#mui/material/ButtonBase';
import { styled } from '#mui/material/styles';
import Typography from '#mui/material/Typography';
import InputBase from '#mui/material/InputBase';
import SearchIcon from '#mui/icons-material/Search';
import AddIcon from '#mui/icons-material/Add';
import { makeStyles } from '#mui/styles'
const useStyles = makeStyles(theme => ({
button: {
...theme.typography.mainmenu,
borderRadius: "40px",
width: "230px",
height: "130px",
marginLeft: "30px",
alignItem: "center",
"&:hover": {
backgroundColor: theme.palette.secondary
},
[theme.breakpoints.down("sm")]: {
width: '100% !important', // Overrides inline-style
height: 100
},
},
}))
/*Image Button Styling Begins*/
const images = [
{
url: '/assets/breakfastMenu.jpg',
title: 'Breakfast',
width: '20%',
},
{
url: '/assets/steak.jpg',
title: 'Mains',
width: '20%',
},
{
url: '/assets/desserts.jpg',
title: 'Desserts',
width: '20%',
},
];
const Image = styled('span')(({ theme }) => ({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
color: theme.palette.common.primary,
}));
const ImageButton = styled(ButtonBase)(({ theme }) => ({
position: 'relative',
height: 150,
[theme.breakpoints.down('sm')]: {
width: '100% !important', // Overrides inline-style
height: 100,
},
'&:hover, &.Mui-focusVisible': {
zIndex: 1,
'& .MuiImageBackdrop-root': {
opacity: 0.15,
},
'& .MuiImageMarked-root': {
opacity: 0,
},
'& .MuiTypography-root': {
border: '4px solid currentColor',
},
},
}));
const ImageSrc = styled('span')({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
backgroundSize: 'cover',
backgroundPosition: 'center 40%',
});
const ImageBackdrop = styled('span')(({ theme }) => ({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
backgroundColor: theme.palette.common.black,
opacity: 0.4,
transition: theme.transitions.create('opacity'),
}));
const ImageMarked = styled('span')(({ theme }) => ({
height: 3,
width: 18,
backgroundColor: theme.palette.common.white,
position: 'absolute',
bottom: -2,
left: 'calc(50% - 9px)',
transition: theme.transitions.create('opacity'),
}));
/*Image Button Styling Ends*/
const Search = styled('div')(({ theme }) => ({
position: 'relative',
borderRadius: theme.shape.borderRadius,
backgroundColor: alpha(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: alpha(theme.palette.common.white, 0.25),
},
marginLeft: 0,
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing(1),
width: 'auto',
},
}));
const SearchIconWrapper = styled('div')(({ theme }) => ({
padding: theme.spacing(0, 2),
height: '100%',
position: 'absolute',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}));
const StyledInputBase = styled(InputBase)(({ theme }) => ({
color: 'inherit',
'& .MuiInputBase-input': {
padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('sm')]: {
width: '12ch',
'&:focus': {
width: '20ch',
},
},
},
}));
const Header = () => {
const classes = useStyles();
return (<React.Fragment>
<AppBar position="sticky" className={classes.appBar}>
<Toolbar disableGutters>
{images.map((image) => (
<ImageButton
focusRipple
key={image.title}
style={{
width: image.width,
}}
>
<ImageSrc style={{
backgroundImage: `url(${image.url})`
}} />
<ImageBackdrop className="MuiImageBackdrop-root" />
<Image>
<Typography
component="span"
variant="subtitle1"
color="white"
fontWeight="bold"
sx={{
position: 'relative',
p: "7em",
pt: "2em",
pb: (theme) => `calc(${theme.spacing(1)} + 6px)`,
}}
>
{image.title}
<ImageMarked className="MuiImageMarked-root" />
</Typography>
</Image>
</ImageButton>
))}
<Button size="large" variant="contained" color="secondary"
startIcon={<AddIcon />}
sx={{
borderRadius: "40px", borderRadius: "40px",
width: "230px",
height: "130px",
marginLeft: "30px",
alignItem: "center",
}} >Add A recipe</Button>
<Button size="large" variant="contained" color="secondary" className={classes.button}>Meals for the Week</Button>
<Search>
<SearchIconWrapper>
<SearchIcon />
</SearchIconWrapper>
<StyledInputBase
placeholder="Search…"
inputProps={{ 'aria-label': 'search' }}
/>
</Search>
</Toolbar>
</AppBar>
</React.Fragment >
)
}
export default Header

Exactly, you need to add some configuration to the _document.tsx in order to make the styles work properly with the NextJS server side rendering feature. The reason behind this is that you need that some styles are injected in the DOM for you.
As you can see in the MUI docs, you can use the ServerStyleSheets to handle the server side rendering properly.
This is the code I have in my _document.tsx
import React from 'react';
import Document, { Html, Main, NextScript } from 'next/document';
import { ServerStyleSheets } from '#mui/styles';
export default class MyDocument extends Document {
render() {
return (
<Html>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
MyDocument.getInitialProps = async (ctx) => {
// Render app and page and get the context of the page with collected side effects.
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) => sheets.collect(<App {...props} />)
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()]
};
};
You can read more information about this in these Server rendering - MUI docs

Related

How to mute remote user in Agora UI kit?

I am using AgoraUIKit from "agora-react-uikit". it is supposed to have the option to mute remote users as per their documentation, but it is not there as they showed in their demo example.
Here is the github link for controls panal which is supposed to be there by default.
https://github.com/AgoraIO-Community/VideoUIKit-Web-React/wiki/Guide#controls
Here is a code of the App.tsx file
import React, { CSSProperties, useState } from 'react'
import AgoraUIKit, { layout, VideoPlaceholderProps, BtnTemplate } from 'agora-react-uikit'
import 'agora-react-uikit/dist/index.css'
const PageComponent: React.FunctionComponent<VideoPlaceholderProps> = ({isShown=true, showButtons=true, showSwap=false}) => {
return (
<>
{showButtons}{isShown}{showSwap}
{BtnTemplate}
</>
);
};
const App: React.FunctionComponent = () => {
const [videocall, setVideocall] = useState(false)
const [isHost, setHost] = useState(true)
const [isPinned, setPinned] = useState(false)
const [username, setUsername] = useState('')
return (
<div style={styles.container}>
<div style={styles.videoContainer}>
{videocall ? (
<>
<div style={styles.nav2}>
<h3 style={styles.heading}>Online Video Call</h3>
<p style={styles.btn} onClick={() => setPinned(!isPinned)}>
Change Layout
</p>
</div>
<AgoraUIKit
rtcProps={{
appId: 'appid',
channel: 'channel name',
uid: 0,
token: 'token', // add your token if using app in secured mode
role: isHost ? 'host' : 'audience',
layout: isPinned ? layout.pin : layout.grid,
activeSpeaker: true,
disableRtm: false,
enableScreensharing: true,
CustomVideoPlaceholder: PageComponent,
}}
rtmProps={{
username: username || 'user',
displayUsername: true,
showPopUpBeforeRemoteMute: true
}}
callbacks={{
EndCall: () => setVideocall(false)
}}
styleProps={{
localBtnContainer: { backgroundColor: 'white', justifyContent: 'center', gap: "20px" },
> BtnTemplateStyles: { borderColor: 'rgb(107 107 107)' },
}}
/>
</>
) : (
<div style={styles.nav}>
<input
style={styles.input}
placeholder='nickname'
type='text'
value={username}
onChange={(e) => {
setUsername(e.target.value)
}}
/>
<h3 style={styles.btn} onClick={() => setVideocall(true)}>
Start Call
</h3>
</div>
)}
</div>
</div>
)
}
const styles = {
container: {
maxWidth: '1100px',
margin: "0 auto",
height: '100vh',
display: 'flex',
flex: 1,
},
container2: {
padding: "2px 16px"
},
heading: { textAlign: 'center' as const, marginBottom: 0 },
videoContainer: {
display: 'flex',
flexDirection: 'column',
flex: 1
} as CSSProperties,
nav: { display: 'flex', justifyContent: 'space-between' },
nav2: { display: 'flex', justifyContent: 'space-between', borderBottom: "1px solid black" },
card: {
// position:"absolute",
// left:"0",
// bottom:"0",
// transform:"translate(155px, -82px)",
// boxShadow: '0 4px 8px 0 rgba(0,0,0,0.2)',
// transition: '0.3s',
// display: 'flex',
// width:"80vw",
// height:"80vh",
// flexDirection: "column",
// justifyContent: "space-between"
} as CSSProperties,
btn: {
backgroundColor: '#007bff',
cursor: 'pointer',
borderRadius: 5,
padding: '4px 8px',
color: '#ffffff',
fontSize: 20
},
input: { display: 'flex', height: 24, alignSelf: 'center' } as CSSProperties
}
export default Apptype here

Button is moved out of the visible content

I've got a problem with my CSS styling. I've got some example headers with the possibility to add some header bookmarks with help of the "PLUS" button. You can see the code here: https://codesandbox.io/s/condescending-feather-wjxfuu?file=/src/App.js or:
import React, { useState } from "react";
export default function App() {
const [list, setList] = useState([]);
const handleAddItem = () => {
const newItem = { id: list.length, name: `Item ${list.length + 1}` };
setList([...list, newItem]);
};
const handleRemoveItem = (index) => {
setList(list.filter((item) => index !== item.id));
};
return (
<div className="App">
<div
style={{
width: "400px",
height: "50px",
display: "flex",
alignItems: "center",
gap: "8px",
overflow: "hidden",
padding: "8px",
border: "1px solid red"
}}
>
{list.map((item, i) => (
<div
key={i}
style={{
border: "1px solid blue",
borderRadius: "5px",
padding: "4px",
backgroundColor: "blue",
color: "white",
cursor: "pointer",
overflow: " hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis"
}}
onClick={() => handleRemoveItem(i)}
>
{item.name}
</div>
))}
<button onClick={handleAddItem}>+</button>
</div>
</div>
);
}
The problem is, that when I add some number of the bookmarks, then in some cases the "PLUS" button starts to overflow the div container(header) as you can see in the GIF.
I want the button not to overflow the content.
You can add another div to keep all your items separate from your button
You can try this playground
import React, { useState } from "react";
export default function App() {
const [list, setList] = useState([]);
const handleAddItem = () => {
const newItem = { id: list.length, name: `Item ${list.length + 1}` };
setList([...list, newItem]);
};
const handleRemoveItem = (index) => {
setList(list.filter((item) => index !== item.id));
};
return (
<div className="App">
<div
style={{
width: "400px",
height: "50px",
display: "flex",
alignItems: "center",
gap: "8px",
overflow: "hidden",
padding: "8px",
border: "1px solid red"
}}
>
<div
style={{
height: "50px",
display: "flex",
alignItems: "center",
gap: "8px",
overflow: "hidden"
}}
>
{list.map((item, i) => (
<div
key={i}
style={{
border: "1px solid blue",
borderRadius: "5px",
padding: "4px",
backgroundColor: "blue",
color: "white",
cursor: "pointer",
overflow: " hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis"
}}
onClick={() => handleRemoveItem(i)}
>
{item.name}
</div>
))}
</div>
<button onClick={handleAddItem}>+</button>
</div>
</div>
);
}
Hi, Simply make the button directly in the div classed app <div className="App">
import React, { useState } from "react";
export default function App() {
const [list, setList] = useState([]);
const handleAddItem = () => {
const newItem = { id: list.length, name: `Item ${list.length + 1}` };
setList([...list, newItem]);
};
const handleRemoveItem = (index) => {
setList(list.filter((item) => index !== item.id));
};
return (
<div className="App">
<div
style={{
width: "400px",
height: "50px",
display: "flex",
alignItems: "center",
gap: "8px",
overflow: "hidden",
padding: "8px",
border: "1px solid red"
}}
>
{list.map((item, i) => (
<div
key={i}
style={{
border: "1px solid blue",
borderRadius: "5px",
padding: "4px",
backgroundColor: "blue",
color: "white",
cursor: "pointer",
overflow: " hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis"
}}
onClick={() => handleRemoveItem(i)}
>
{item.name}
</div>
))}
</div>
<button onClick={handleAddItem}>+</button>
</div>
);
}

opening a react select dropdown inside a div is pushing another div in the same parent

I am using react-select and have generated few dropdowns. However, when I click on the top div, its pushing the bottom one below. I am using flex to display them inline. Could someone please help with my below issues. Really appreciate your help!
Opening/closing a div should not affect the other div. The expanded dropdown should overlay the botton div
Selecting an option from one drop down is selecting from the rest as well
Dropdowns are not getting clicked at times
I am very new to CSS/React. Please help me. Below is the code:
const customStyles = {
control: (provided, state)=> ({
...provided,
width: 210,
position: 'relative',
top: 40,
// height: 25,
// minHeight: 10,
// overflow:'hidden'
}),
menu: (provided, state) => ({
...provided,
width: 210,
position: 'relative',
top: 40
}),
menulist: (provided, state) => ({
...provided,
width: 210,
}),
option: (provided, state) => ({
...provided,
width: 210,
height: 24,
minHeight: 15,
paddingTop:0,
fontSize: '0.8em',
}),
placeholder: (provided, state) => ({
...provided,
fontSize: '0.8em',
color: colourOptions[1].color,
fontWeight: 400,
// position: 'relative',
// top: 2,
overflow:'hidden'
}),
multiValue: (styles, { data }) => {
const color = colourOptions[0].color;
return {
...styles,
backgroundColor: colourOptions[0].color
};
},
multiValueLabel: (styles, { data }) => ({
...styles,
color: 'white',
height: 18,
minHeight: 15,
fontSize:12,
paddingTop:0
}),
multiValueRemove: (styles, { data }) => ({
...styles,
color: colourOptions[1].color,
':hover': {
backgroundColor: colourOptions[0].color,
color: 'white',
},
}),
dropdownIndicator : (styles, { data }) => ({
...styles,
color: colourOptions[1].color,
size:6,
':hover': {
color: colourOptions[0].color,
},
}),
};
class DefectsContainer extends Component {
state = {
teams: [{ value: 'a', label: 'Alpha' },
{ value: 'b', label: 'Beta' },
{ value: 'c', label: 'Gamma' }],
selectedOption:null
};
handleChange = selectedOption => {
this.setState(
{ selectedOption },
() => console.log(`Option selected:`, this.state.selectedOption)
);
};
render() {
const { selectedOption } = this.state;
return (
<div className="defect-dashboard-main-div">
<div className="defect-dashboard-container">
<div className="filterContainer">
<div className="filterChildDiv">
<label className="filterHeader">Project</label>
<Select className="select-teams" closeMenuOnSelect={false} isMulti options={this.state.teams}
autosize={false} value={selectedOption} onChange={this.handleChange} styles={customStyles}
placeholder="Select Project(s)..." theme={theme => ({
...theme,
borderRadius: 3,
borderColor: colourOptions[0].color,
colors: {
...theme.colors,
primary25: 'hotpink'
}
})}
/>
</div>
<div className="filterChildDiv">
<label className="filterHeader">Category</label>
<Select className="select-teams" closeMenuOnSelect={false} isMulti options={this.state.teams}
autosize={false} value={selectedOption} onChange={this.handleChange} styles={customStyles}
placeholder="Select Category..." theme={theme => ({
...theme,
borderRadius: 3,
borderColor: colourOptions[0].color,
colors: {
...theme.colors,
primary25: 'hotpink'
}
})}
/>
</div>
....
My css file:
.filterContainer{
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
}
.filterChildDiv{
flex: 1;
/* float: left; */
margin-right: 20px;
}
.defect-dashboard-table-env-main{
width:1400px!important;
height: 1050px!important;
position: absolute;
top:40px;
left:120px;
}
By default, the select menu is styled with absolute position, which allows it to overlay other elements by removing the element from the document flow. In your custom styles, you set menu position to relative, so the other relatively positioned elements move when the menu is opened and inserted into the document flow. Removing position: relative from the object returned by your customStyles.menu function will fix the issue.
The dropdown menu has css position: absolute, so it's bound to the parent container. As a result the dropdown menu changes the height of the parent container which is problematic in some cases, e.g. if the parent container is some kind modal dialog.
In those cases the dropdown menu should mimic the original behavior of selects where it overlaps other elements on the page. In order to achieve this behavior the dropdown menu must have position:fixed and the positioning (top, left, right) must be handled manually. It has to be attached to the position of the select control and the position must be manually change when scrolling the viewport.
const selectStyles = {
valueContainer: () => ({
padding: 10,
display: "flex",
alignItems: "center"
}),
menu: () => ({
zIndex: 50,
position: "fixed",
backgroundColor: "#fff"
}),
}
<Select
styles={selectStyles}
//...
/>

react how can fit div width like android wrap-content?

const SearchBar = (text, onChange) => {
return (
<div>
<div style={{flexWrap: "wrap", background: 'red', border: "1px solid", borderRadius: 10}}>
<Search style={{background: 'blue', verticalAlign: 'bottom'}}/>
<input style={{background: 'blue', verticalAlign: 'bottom'}}
text={text} onChange={onChange}/>
</div>
</div>
);
};
export default SearchBar;
Here is my search bar code.
The result is
but, I want it to appear like this.
How can I get the result?
In your Search component make the width to be 100%.
<Search style={{background: 'blue', verticalAlign: 'bottom', width:'100%'}}/>
First import FaSearch then replace your code with below mentioned.
import { FaSearch } from "react-icons/fa";
const App =(text, onChange)=> {
return (
<>
<div style={styles.mainStyle}>
<Search />
<input style={styles.inputStyle} text={"text"} onChange={null} />
</div>
</>
);
}
const Search = () => <FaSearch style={styles.search} />;
const styles = {
mainStyle: {
display: "flex",
flexWrap: "wrap",
borderRadius: 10,
alignItems: "center",
border: "1px solid",
overflow: "hidden"
},
inputStyle: {
flex: 1,
border: "none",
height: 30
},
search: {
fontSize: 30,
padding: "0px 10px",
cursor: "pointer",
borderRight: '1px solid grey'
}
};

ReactNativeDisplay Json file in another format

rookie in RN, thanks in advance! I want to display a json file on a page.
This is the format of the json:
{
"prediction": [
{ "name":"egg", "value":"0.95" },
{ "name":"apple", "value":"0.02" },
{ "name":"peach", "value":"0.01" },
{ "name":"orange", "value":"0.01" },
{ "name":"fish", "value":"0.01" }
]
}
Assuming the Name of the json will be " /app/prediction.json ".
And the text input method I had on this page will be :
import { Tile, List, ListItem, Button } from 'react-native-elements';
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Dimensions,
View
} from 'react-native';
export default class ProjectOne extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.text}> Analysis </Text>
<Text> The object has " 95% possibility to be an egg, 40% to be an apple "</Text>
</View>
);
}
}
const styles = StyleSheet.create({
text: {
fontSize: 20,
fontWeight: 'bold',
},
container: {
height: 275,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
height: Dimensions.get('window').height,
width: Dimensions.get('window').width
},
capture: {
flex: 0,
backgroundColor: 'black',
borderRadius: 5,
color: '#ffffff',
padding: 10,
margin: 40
}
});
AppRegistry.registerComponent('ProjectOne', () => ProjectOne);
Is there any way that I can fetch the json file, and then, display the json content into that text field on this page?
You can do it by using require('./app/prediction.json') then convert it to string or format if needed