React Material UI textfield label problem - reactjs

I have problem with material ui text field.
There is a form with more textinput. When I scroll down the page, the textinputs label overlap on the header. Could You any idea solve this problem.
Thank You for Your help!
Without scrolling
Scrolling
Code Sandbox: https://codesandbox.io/s/serverless-night-wpkrb?file=/src/App.js
Code from sandbox below:
textinput.js
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
const useStyles = makeStyles((theme) => ({
root: {
"& > *": {
margin: theme.spacing(1),
width: "25ch"
}
}
}));
const id = (error) => {
if (error === true) {
return "outlined-error";
} else {
return "outlined";
}
};
const shrink = (arg) => {
// ez a func biztosítja, hogy teljes label legyen és ne legyen kezelési hiba
if (arg === "") {
return false;
} else {
return true;
}
};
export default function BasicTextFields(props) {
const classes = useStyles();
return (
<form className={classes.root} noValidate autoComplete="off">
<TextField
error={props.error}
id={id(props.error)}
label={props.label}
variant="outlined"
onChange={props.change}
style={{ width: props.width }}
value={props.value}
InputLabelProps={{ shrink: shrink(props.value) }}
type={props.type}
inputProps={{ maxLength: props.maxlength }}
/>
</form>
);
}
App.js
import React from "react";
import "./styles.css";
import "w3-css/w3.css";
import BasicTextFields from "./textinput";
export default function App() {
return (
<div className="body">
<div className="w3-top w3-padding-8 w3-border-bottom w3-border-black">
<div className="w3-center w3-padding-16">
<div className="t1">
TündErella - <span style={{ fontSize: 45 }}> some text here.</span>{" "}
</div>
</div>
</div>
<div style={{ marginTop: 200 }}>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
<div className="name">
<BasicTextFields label="Vezetéknév: *"></BasicTextFields>
<BasicTextFields label="Keresztnév: *"></BasicTextFields>
</div>
<div className="name">
<BasicTextFields label="Vezetéknév: *"></BasicTextFields>
<BasicTextFields label="Keresztnév: *"></BasicTextFields>
</div>
<div className="name">
<BasicTextFields label="Vezetéknév: *"></BasicTextFields>
<BasicTextFields label="Keresztnév: *"></BasicTextFields>
</div>
<div className="name">
<BasicTextFields label="Vezetéknév: *"></BasicTextFields>
<BasicTextFields label="Keresztnév: *"></BasicTextFields>
</div>
</div>
);
}
styles.css
.App {
font-family: sans-serif;
text-align: center;
}
.body {
border: 1px solid white;
/*background-image: url("./static/background_maarten-deckers_1.jpg");*/
background-color: ivory;
}
.w3-top {
background-color: #daf0da;
}
.t1 {
font-size: 60px;
font-family: "Great Vibes", cursive;
}

The label for outlined TextField is rendered with a z-index of 1. This is the same z-index as applied by w3-top.
You need to bump up the z-index of w3-top in your styles.css:
.w3-top {
background-color: #daf0da;
z-index: 2;
}
In order for these styles to win over the styles defined in w3-css, you need to flip the order of your imports
from:
import "./styles.css";
import "w3-css/w3.css";
to:
import "w3-css/w3.css";
import "./styles.css";
Here's a working example: https://codesandbox.io/s/override-w3-top-z-index-k5fjv?file=/src/styles.css:198-252

Related

how to change only current component style on hover

I have a requirement where I need to highlight the component on hover
I have two styles defined baseStyle and highlight
<div style={{ background: '#fff' }}>
<div
onMouseEnter={(e) => setToolStyle({ ...baseStyle, ...highlight })}
onMouseLeave={e => setToolStyle(baseStyle)}
style={toolStyle}>
<FontAwesomeIcon icon={faMousePointer} style={{ fontSize: "20px" }} />
</div>
<div
onMouseEnter={(e) => setToolStyle({ ...baseStyle, ...highlight })}
onMouseLeave={e => setToolStyle(baseStyle)}
style={toolStyle}>
<FontAwesomeIcon icon={faMousePointer} style={{ fontSize: "20px" }} />
</div>
</div>
Expected Output:
on hovering any of the component only that component must be highlighted(i.e just need to add highlight css class to it).
but right now all the component is getting highlighted because of toolStyle state. can anyone help me on this by giving some logic.
Here is an example
you can create a small component with the highlight effect
and use it component any number of times and from anywhere
(As I said in comments )
https://codesandbox.io/s/laughing-mclaren-4i8en?file=/src/highlight.js
child.js
import { useState } from "react";
const baseStyle = { color: "black", fontSize: 14 };
const highlight = { color: "red" };
export default function Highlight({ text }) {
const [toolStyle, setToolStyle] = useState(baseStyle);
return (
<div
onMouseEnter={(e) => setToolStyle({ ...baseStyle, ...highlight })}
onMouseLeave={(e) => setToolStyle(baseStyle)}
style={toolStyle}
>
{text}
</div>
);
}
parent.js
import Highlight from "./highlight";
import "./styles.css";
export default function App() {
return (
<div>
<Highlight text="text 1" />
<Highlight text="text 2" />
<Highlight text="text 3" />
</div>
);
}
This is the best way to implement this with code reusability and
less of code duplication
You can do something like this:
export default function App() {
let [hovered, setHovered] = React.useState({ div1: false, div2: false });
return (
<div>
<div
className={hovered.div1 ? 'hovered' : ''}
onMouseEnter={(e) => setHovered((ps) => ({ ...ps, div1: true }))}
onMouseLeave={(e) => setHovered((ps) => ({ ...ps, div1: false }))}
>
Hello
</div>
<div
className={hovered.div2 ? 'hovered' : ''}
onMouseEnter={(e) => setHovered((ps) => ({ ...ps, div2: true }))}
onMouseLeave={(e) => setHovered((ps) => ({ ...ps, div2: false }))}
>
Hello
</div>
</div>
);
}
You can move your styles to CSS file and avoid extra complexity:
App.js
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faCoffee } from "#fortawesome/free-solid-svg-icons";
import "./App.css";
function App() {
return (
<div className="wrapper">
<div>
<FontAwesomeIcon icon={faCoffee} />
</div>
<div>
<FontAwesomeIcon icon={faCoffee} />
</div>
</div>
);
}
export default App;
App.css
.wrapper {
background: #fff;
}
.wrapper > div {
color: red;
font-size: 20px;
}
.wrapper > div:hover {
color: green;
cursor: pointer;
}

How to update the state in different mobile screens using React Hooks

I am working on React project, In that I have a button under that I have another div, I written a function if My screen width is 320px then margin-bottom: 150px has to apply under button. it is working fine, but when I am in 320px screen if I click the button then under button margin-bottom: 150px is applied. Here the problem comes now when I go to 375 px here also margin-bottom: 150 px applied automatically. so someone help to how to update state in 375px. Because in 375px screen I have to apply margin-bottom: 300 px.
If you have any questions please let me know thank you.
This is My code
This is App.js
import React, { useState, useLayoutEffect } from 'react';
import './App.css';
const App = () => {
const [style, setStyle] = useState(null)
function useMediaQuery() {
const [screenSize, setScreenSize] = useState([0]);
useLayoutEffect(() => {
function updateScreenSize() {
setScreenSize([window.innerWidth]);
}
window.addEventListener("resize", updateScreenSize);
updateScreenSize();
return () => window.removeEventListener("resize", updateScreenSize);
}, []);
return screenSize;
}
const [mediaQuery] = useMediaQuery();
console.log(mediaQuery, '***')
const applyStyle = () => {
if(mediaQuery === 320) {
setStyle({
marginBottom: '150px'
})
}
}
return (
<div className='container'>
<div className='row'>
<div className='col-12'>
<div className='first'>
<button onClick={applyStyle} style={style} className='btn btn-primary'>Click here</button>
<span className='closeWindow'><i className="far fa-window-close"></i></span>
</div>
<div className='second'>
</div>
</div>
</div>
</div>
)
}
export default App
in App.css write a #media query:
#media screen and (max-width: 375px) {
button {
margin-bottom: 300px;
}
}
You can apply media queries in React either programmatically, or using css.
Option 1, using css:
.myButton{
/* media queries */
#media (max-width: 320px) {
margin-bottom: 150px;
}
#media (max-width: 375px) {
margin-bottom: 300px;
}
}
and then:
return (
<div className='container'>
<div className='row'>
<div className='col-12'>
<div className='first'>
<button onClick={applyStyle} className='myButton btn btn-primary'>Click here</button>
<span className='closeWindow'><i className="far fa-window-close"></i></span>
</div>
<div className='second'>
</div>
</div>
</div>
</div>
)
Option 2, programmatically:
import React, { useState, useEffect, useLayoutEffect } from 'react';
import './App.css';
const App = () => {
const [mediaMatch, setMediaMatch] = useState();
const handler = e => setMediaMatch(e.matches);
useEffect(() => {
window.matchMedia('(min-width: 768px)').addListener(handler);
return () => {
window.removeEventListener(handler);
};
}, []);
return (
<div className="container">
<div className="row">
<div className="col-12">
<div className="first">
<button
onClick={applyStyle}
style={{
marginBottom: mediaMatch ? '300px' : '150px'
}}
className="btn btn-primary"
>
Click here
</button>
<span className="closeWindow">
<i className="far fa-window-close" />
</span>
</div>
<div className="second" />
</div>
</div>
</div>
);
};

Why my react-bootstrap Accordion is not working on small devices?

I have a simple Accordion in one of my components.
function CustomToggle({eventKey}) {
const [children, setChildren] = useState('Mais filtros 🠗')
const decoratedOnClick = useAccordionToggle(eventKey, () =>
setChildren(children === 'Mais filtros 🠗' ? 'Menos filtros 🠕' : 'Mais filtros 🠗')
)
return (
<div className="text-center">
<div className="tag align-center" onClick={decoratedOnClick}>
{children}
</div>
</div>
)
}
...
<Accordion>
<CustomToggle eventKey="0" />
<Accordion.Collapse eventKey="0">
<QueryForm
baseEndpoint={this.props.baseEndpoint}
tagsInitialValues={this.state.searchParams.tags}
textInitialValue={this.state.searchParams.description}
setSearchParams={this.setSearchParams}
/>
</Accordion.Collapse>
</Accordion>
It works perfectly on larger breakpoints, but, for smaller devices, the QueryForm shows in the opposite direction and stays on top of the page's content.
Check the sandbox: https://codesandbox.io/s/0y8cm
(click on 'Mais filtros' to trigger the accordion and see the problematic breakpoint when the navbar toggle appears)
What am I doing wrong?
The default of Accordion react component it doesn't use absolute position for define the position of the accordion content. I'm not sure how you customize position: absolute. Then the first way if you consider don't need to use the position: absolute. You can remove it at:
collapsing {
position: absolute !important;
z-index: 3;
width: 100%;
top: 75px;
}
.collapse.show {
display: block;
position: absolute;
z-index: 3;
width: 100%;
top: 75px;
}
The second way, if you intend to do something with position: absolute in mobile, you should pick a container of the form and add position: relative then your form will render base on the position of that container.
<div style={{ position: "relative" }}>
<Accordion>
<CustomToggle eventKey="0" />
<Accordion.Collapse eventKey="0">
<QueryForm
baseEndpoint={this.props.baseEndpoint}
tagsInitialValues={this.state.searchParams.tags}
textInitialValue={this.state.searchParams.description}
setSearchParams={this.setSearchParams}
/>
</Accordion.Collapse>
</Accordion>
</div>
There is some issue in your Navbar.css. Not sure why you use position to be absolute. I commented out those, and it works now.
.collapsing {
/* position: absolute !important; */
/* z-index: 3; */
width: 100%;
/* top: 75px; */
}
.collapse.show {
display: block;
/* position: absolute; */
/* z-index: 3; */
width: 100%;
/* top: 75px; */
}
https://codesandbox.io/s/relaxed-dust-2yimw?file=/src/components/common/Navbar.css:736-984
Do you run the Accordian on small device?
here is my code. I hope it's will help you.
import React, {useState} from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Accordion from '#material-ui/core/Accordion';
import AccordionSummary from '#material-ui/core/AccordionSummary';
import AccordionDetails from '#material-ui/core/AccordionDetails';
import Typography from '#material-ui/core/Typography';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import PropTypes from 'prop-types';
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
},
heading: {
fontSize: theme.typography.pxToRem(1),
fontWeight: theme.typography.fontWeightRegular,
},
}));
const Accordian = ({
title,
data,
onclick,
shownName
}) =>{
const classes = useStyles();
let content;
const [subtitle, setSubtitle] = useState("");
const [expand, setExpand] = useState(true);
const liClick = (e) => {
setSubtitle(e.target.getAttribute('data'));
onclick(e);
setExpand(!expand);
}
const clickExpand = (e) =>{
setExpand(!expand);
}
content = data.map((value, key)=>{
return (
<li
className="list-group-item"
key={data[key][shownName]+"_"+key}
name={data[key][shownName]}
data={data[key][shownName]}
onClick={liClick}
>
{data[key].mark?(<img src={data[key].mark} align="left" className="mark_sign" alt="mark"/>):''}
{data[key][shownName]}
<i className="fa fa-angle-right" align="right"/>
</li>
);
});
return (
<div className={classes.root}>
<div className="container">
<Accordion
defaultExpanded={true}
expanded={expand}
style={{
borderBottom:'1px',
borderBottomColor:'white',
borderBottomStyle:'solid'
}}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography
className={classes.heading}
style={{fontSize:'14px', textAlign:'left'}}
onClick={clickExpand}
>
<span className="Name" style={{ float:'left'}}>{title}{' '}</span>
<span style={{fontSize:'18px', color:'#007bff',width:'100%',top:'10px',left:'0', textAlign:'center', position:'absolute'}}>{' '}{subtitle}</span>
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
<span
className="list-group list-group-flush"
align="center"
>
{content}
</span>
</Typography>
</AccordionDetails>
</Accordion>
</div>
</div>
);
}
Accordian.propTypes = {
shownName: PropTypes.string.isRequired,
data: PropTypes.array.isRequired,
onclick: PropTypes.func.isRequired
};
export default Accordian;
Yesterday I fix the this problem. So I share this code.
Please check agian.

ReactJS DropZone browser attempts to open file on drop

Trying to implement the Dropzone component but not have much luck. Am I missing something here?
import { useState } from 'react';
import { useDropzone } from 'react-dropzone';
import styled from 'styled-components';
export const FilDataForm = (props) => {
const [files, setFiles] = useState([])
const getColor = (props) => {
if (props.isDragAccept) return '#00e676';
if (props.isDragReject) return '#ff1744';
if (props.isDragActive) return '#2196f3';
return '#eeeeee';
}
const onDrop = (file) => {
console.log('HERE!!!!!')
let nf = files;
nf.push(file)
setFiles(nf)
}
const Container = styled.div`
flex:1;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
border-width: 2px;
border-radius: 2px;
border-color: ${props => getColor(props)};
border-style: dashed;
background-color: #fafafa;
color: #bdbdbd;
outline: none;
transition: border .24s ease-in-out;
`
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone(onDrop);
return (
<div className="modal">
<div className="dialog" style={{ width: "25%", marginBottom: "50px" }}>
<div className="header"><h2>File Uploader</h2></div>
<div className="content">
<Container {...getRootProps({ isDragActive, isDragAccept, isDragReject })}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</Container>
<div className="grid-container" style={{ marginTop: "20px", height: "250px" }}></div>
</div>
</div>
</div>
)
}
Dragging the file(s) into the drop area causes the browser to launch a new tab attempting to open the file. Any help is appreciated.
EDIT
Clicking in the Dropzone does not open the file dialog either.
You need to prevent the default event.
I'm using Class component based React Dropzone and this is how i have stopped the default event.
{...getRootProps({
className: 'dropzone',
onDrop: (event) => event.preventDefault(),
})}
Complete Code
<Dropzone onDrop={ (files) => fileHandling(files) } >
{({ getRootProps, getInputProps }) => (
<div
{...getRootProps({
className: 'dropzone',
onDrop: (event) => event.preventDefault(),
})}
style={{ border: '1px solid #707070' }}
>
<input {...getInputProps()} />
<h3 style={{ cursor: 'pointer' }}>
Drag & Drop file or click here to Upload
</h3>
</div>
)}
</Dropzone>
Hope it helps

Full screen drag and drop files in React

In this official example of react-dropzone, a full screen drop zone is achieved by wrapping the whole app inside the <Dropzone /> component. I am creating a multi route app and feel that wrapping everything inside the <Dropzone /> component is not a very clean solution.
Is there a way to create a full screen/page drop zone in React without placing the <Dropzone /> component on the root level?
Create a route to a Dropzone form and adjust the height and size of the field by utilizing CSS.
Working example: https://codesandbox.io/s/l77212orwz (this example uses Redux Form, but you don't have to)
container/UploadForm.js
import React, { Component } from "react";
import { reduxForm } from "redux-form";
import ShowForm from "../components/showForm";
class UploadImageForm extends Component {
state = { imageFile: [] };
handleFormSubmit = formProps => {
const fd = new FormData();
fd.append("imageFile", formProps.imageToUpload[0]);
// append any additional Redux form fields
// create an AJAX request here with the created formData
};
handleOnDrop = newImageFile => this.setState({ imageFile: newImageFile });
resetForm = () => {
this.setState({ imageFile: [] });
this.props.reset();
};
render = () => (
<div style={{ padding: 10 }}>
<ShowForm
handleOnDrop={this.handleOnDrop}
resetForm={this.resetForm}
handleFormSubmit={this.handleFormSubmit}
{...this.props}
{...this.state}
/>
</div>
);
}
export default reduxForm({ form: "UploadImageForm" })(UploadImageForm);
components/showForm.js
import isEmpty from "lodash/isEmpty";
import React from "react";
import { Form, Field } from "redux-form";
import DropZoneField from "./dropzoneField";
const imageIsRequired = value => (isEmpty(value) ? "Required" : undefined);
export default ({
handleFormSubmit,
handleOnDrop,
handleSubmit,
imageFile,
pristine,
resetForm,
submitting
}) => (
<Form onSubmit={handleSubmit(handleFormSubmit)}>
<Field
name="imageToUpload"
component={DropZoneField}
type="file"
imagefile={imageFile}
handleOnDrop={handleOnDrop}
validate={[imageIsRequired]}
/>
<button
type="submit"
className="uk-button uk-button-primary uk-button-large"
disabled={submitting}
>
Submit
</button>
<button
type="button"
className="uk-button uk-button-default uk-button-large"
disabled={pristine || submitting}
onClick={resetForm}
style={{ float: "right" }}
>
Clear
</button>
</Form>
);
components/dropzoneField.js
import React, { Fragment } from "react";
import DropZone from "react-dropzone";
import { MdCloudUpload } from "react-icons/md";
import RenderImagePreview from "./renderImagePreview";
export default ({
handleOnDrop,
input,
imagefile,
meta: { error, touched }
}) => (
<div>
<DropZone
accept="image/jpeg, image/png, image/gif, image/bmp"
className="upload-container"
onDrop={handleOnDrop}
onChange={file => input.onChange(file)}
>
<div className="dropzone-container">
<div className="dropzone-area">
{imagefile && imagefile.length > 0 ? (
<RenderImagePreview imagefile={imagefile} />
) : (
<Fragment>
<MdCloudUpload style={{ fontSize: 100, marginBottom: 0 }} />
<p>Click or drag image file to this area to upload.</p>
</Fragment>
)}
</div>
</div>
</DropZone>
{touched && error && <div style={{ color: "red" }}>{error}</div>}
</div>
);
components/renderImagePreview.js
import map from "lodash/map";
import React from "react";
export default ({ imagefile }) =>
map(imagefile, ({ name, preview, size }) => (
<ul key={name}>
<li>
<img src={preview} alt={name} />
</li>
<li style={{ textAlign: "center" }} key="imageDetails">
{name} - {size} bytes
</li>
</ul>
));
styles.css
.dropzone-container {
text-align: center;
background-color: #efebeb;
height: 100%;
width: 100%;
}
.dropzone-area {
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.upload-container {
height: 100vh;
width: 100%;
margin-bottom: 10px;
}
ul {
list-style-type: none;
}
p {
margin-top: 0;
}

Resources