I have built a React web application. I use tailwind but some own CSS.
I have an input range that uses different data. When I switch the data the input slider thumb is not at the beginning because the data static (here: 300).
But if I change dynamic min={data.width} will not move at all because the min value continuously changes as I change.
How reach that only change min value when I switch between components and not when I use range slider (and stand thumb the beginning of slider when I switch component)?
So when the table is active, the start width at 60cm and stand at the beginning of slider and not a little further.
(Originally I used context have several components that get data by api request from JSON server, but I simplified the scenario).
StackoverflowRange.jsx
import React, { useState } from "react";
const StackoverflowRange = () => {
const [data, setData] = useState({
id: 1,
name: "Chair",
width: "300",
high: "860",
depth: "550",
});
const chair={
id: 1,
name: "Chair",
width: "300",
high: "860",
depth: "550",
}
const table={
id: 1,
name: "Table",
width: "600",
high: "860",
depth: "550",
}
const clickHandler =(item)=>{
if(item=='table'){
setData(table)
}else{
setData(chair)
}
}
const widthHandler = (event) => {
const newWidth = { ...data, width: event };
setData(newWidth);
};
return (
<>
<div className="flex flex-col justify-center md:flex-row">
<div className="m-2">
<div className="m-2">
<div className="slidecontainer">
<h1> {data.name}</h1>
<h1>width: {data.width / 10} cm</h1>
<input
type="range"
min="300"
max="1200"
step="50"
value={data.width}
onChange={(e) => widthHandler(e.target.value)}
className={`slider myslider`}
/>
</div>
</div>
<button
className={`m-2
p-2
w-36
md:w-36
max-w-sm
bg-neutral-100
border-2
rounded-lg
shadow-lg
`}
onClick={()=>clickHandler('table')}
>
Table
</button>
<button
className={`m-2
p-2
w-36
md:w-36
max-w-sm
bg-neutral-100
border-2
rounded-lg
shadow-lg
`}
onClick={()=>clickHandler('chair')}
>
Chair
</button>
</div>
</div>
</>
);
};
export default StackoverflowRange;
own.css
.slider {
-webkit-appearance: none;
height: 7px;
}
.slidecontainer {
width: 100%;
}
.slider {
-webkit-appearance: none;
width: 200px;
height: 7px;
border-radius: 5px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: 0.2s;
transition: opacity 0.2s;
}
.slider:hover {
opacity: 1;
}
.myslider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 25px;
height: 25px;
border-radius: 50%;
cursor: pointer;
}
.myslider {
background: linear-gradient(90deg, white 10%, #57534e 90%);
}
.myslider::-webkit-slider-thumb {
background: #57534e;
}
.mybackground {
background-repeat: repeat-y;
}
Related
I have an editor and several buttons above it on the right. I would like to have a panel just under Button2 that overlays the editor. Then, clicking on Button2 will expand and collapse the panel (which will be easy to implement).
I have written the following code: https://codesandbox.io/s/fervent-mclaren-3mrtyj?file=/src/App.js. At the moment, the panel is NOT under Button2 and does NOT overlay the editor.
Does anyone know how to amend the CSS?
import React from "react";
import { Stack } from "#fluentui/react";
export default class App extends React.Component {
render() {
return (
<div>
<Stack horizontal horizontalAlign="space-between">
<div>Title</div>
<div>Button1 Button2 Button3</div>
</Stack>
<div
style={{
backgroundColor: "yellow",
width: "350px",
height: "50px"
}}
>
A floating panel which is supposed to be always under "Button2" and
overlays the editor.
</div>
<div
style={{
backgroundColor: "gray",
width: "100%",
height: "300px"
}}
>
An editor
</div>
</div>
);
}
}
You need to use position:absolute on floating pane and add it in the editor div which will have position:relative.You can see the result it works fine
On clicking button 2 the floating panel hides/shows alternatively
This will work.
var btn=document.querySelector('.drop_btn');
btn.onclick=function()
{
document.querySelector('.dropdown').classList.toggle('block');
}
*
{
font-family: 'arial';
margin: 0px;
padding: 0px;
}
.menu_pane
{
display: flex;
background: #151515;
color: white;
padding:5px 10px;
align-items: center;
border-bottom: 1px solid rgba(255,255,255,0.2);
}
.menu_pane h3
{
font-weight: normal;
font-size: 18px;
flex-grow: 1;
}
.menu_pane .btn button
{
position: relative;
background: #0971F1;
color: white;
border-radius: 5px;
border:none;
cursor: pointer;
padding: 8px 20px;
margin-right: 10px;
}
.dropdown
{
display: none;
height: 100%;
width: 100%;
top: 0;
left: 0;
color: white !important;
position: absolute;
background: #242424;
border-radius: 0 0 10px 10px;
}
.menu_pane .btn .dropdown p
{
font-size: 14px;
}
.editor_pane
{
position: relative;
background:#151515;
color: white;
min-height: 50vh;
border-radius: 0 0 10px 10px;
padding: 10px;
color: #512DA8;
}
.block
{
display: block;
}
<div class="container">
<div class="menu_pane">
<h3>Title</h3>
<div class="btn">
<button>Button-1</button>
</div>
<div class="btn">
<button class="drop_btn">Button-2</button>
</div>
<div class="btn">
<button>Button-3</button>
</div>
</div>
<div class="editor_pane">
<p>An editor</p>
<div class="dropdown">
<p>A floating panel which is supposed to be always under "Button2" and overlays the editor.</p>
</div>
</div>
</div>
How does this look?
https://codesandbox.io/s/hidden-platform-q3v4kc?file=/src/App.js
I moved the floating pane into the button, made the button position relative, and made the floating pane position absolute.
Note: notice there's no top property on the floating pane. One neat thing about position absolute is if you don't set top, left, bottom, right those positions will be where that box would be if it wasn't position absolute.
Update
I noticed that the overlay needed to cover the "editor" area only and have the example updated with hopefully the right placement of it.
Updated live example: codesandbox
import React from "react";
import { Stack } from "#fluentui/react";
export default class App extends React.Component {
state = { showOverlay: true };
handleToggle = () =>
this.setState((prev) => ({ showOverlay: !prev.showOverlay }));
render() {
return (
<div>
<Stack
horizontal
horizontalAlign="space-between"
style={{ padding: "12px" }}
>
<div>Title</div>
<Stack horizontal>
<button>Button1</button>
<button onClick={this.handleToggle}>
{`Button2 (${this.state.showOverlay ? "Hide" : "Show"} Overlay)`}
</button>
<button>Button3</button>
</Stack>
</Stack>
<div
style={{
backgroundColor: "gray",
width: "100%",
height: "300px",
position: "relative"
}}
>
An editor
<div
style={{
position: "absolute",
inset: "0",
backgroundColor: "rgba(0, 0, 0, 0.70)",
display: this.state.showOverlay ? "flex" : "none",
justifyContent: "center",
alignItems: "center",
color: "#fff"
}}
>
A floating panel which is supposed to be always under "Button2" and
overlays the editor.
</div>
</div>
</div>
);
}
}
Keeping the original example (it had overlay on the whole component except for "Button 2") just in case if it might be useful.
Original
Not sure if I fully understand the desired result, but here is the component implemented with a toggle overlay controlled by Button2.
The overlay is currently set on top of and blocking all child elements except for Button2, so that it works as a "start editing" button, but it can be further adjusted to specify which element it covers to better suit the use case.
Quick demo of the example: codesandbox
import React from "react";
import { Stack } from "#fluentui/react";
export default class App extends React.Component {
state = { showOverlay: true };
handleToggle = () =>
this.setState((prev) => ({ showOverlay: !prev.showOverlay }));
render() {
return (
<div style={{ position: "relative", zIndex: "1" }}>
<Stack
horizontal
horizontalAlign="space-between"
style={{ padding: "12px" }}
>
<div>Title</div>
<Stack horizontal>
<button>Button1</button>
<button style={{ zIndex: "75" }} onClick={this.handleToggle}>
{`Button2 (${this.state.showOverlay ? "Hide" : "Show"} Overlay)`}
</button>
<button>Button3</button>
</Stack>
</Stack>
<div
style={{
position: "absolute",
inset: "0",
backgroundColor: "rgba(0, 0, 0, 0.70)",
zIndex: "50",
display: this.state.showOverlay ? "flex" : "none",
justifyContent: "center",
alignItems: "center",
color: "#fff",
}}
>
A floating panel which is supposed to be always under "Button2" and
overlays the editor.
</div>
<div
style={{
backgroundColor: "gray",
width: "100%",
height: "300px",
}}
>
An editor
</div>
</div>
);
}
}
I'm hitting an API to get these data. I mapped the data to my select menu. I'm not able to change the height of the dropdown box . any idea on how it can be achieved?
react.js
inside render
<div className={styles.nationality}>
<label htmlFor="nationality">Nationality<span className={styles.star}>*</span></label><br/>
{/* <img className={styles.nationalitydrop} src={drop} alt='drop' /> */}
{['nationality'].map(key => (
<select
key={key}
className={styles.nationalitybox}
type="text"
placeholder="select"
menuPlacement="bottom"
onChange={(event) => this.handleUserInput(event)}
value={this.state.nationality}
name='nationality'
> {this.props.nationalityData.map(({[key]:id}) => <option className={styles.data}key={id}>{id}</option>)}
</select>
))}
</div>
stylesheet
.nationalitybox
{
width: 408px;
height: 56px;
background: #30333F 0% 0% no-repeat padding-box;
border-radius: 3px;
opacity: 1;
color: #B4B6C4;
font-size: 20px;
border-style:none none solid;
outline: none;
}
.nationalitybox:placeholder-shown{
font-size: 14px;
color: #B4B6C4;
}
.data{
background-color: #B4B6C4;
color: black;
width: 220px;
}
[![dropdown][1]][1]
I think you are using wrong to style your select menu, you cannot use 'style.nationalitybox' because that not a class.
I suggest you use these options.
1st Option:
Change className={styles.nationalitybox} To className = "nationalitybox".
2nd Option:
If you are using Material UI then you have to use useStyles above the component.
For example:
const useStyles = makeStyles((theme) => ({
nationalitybox: {
height: "56px"
}
}));
const ComponentName = () => {
const styles= useStyles();
}
I am trying to make a slide out drawer utilizing the npm package react-transition-group. For whatever reason, I cannot seem to get the drawer to slide out from left to right on clicking the additional criteria button. If you can solve this issue without using the package, that is ok too!
Here is the code I am trying to get to work as a React component:
{/* DeveloperSearch.js */}
<CSSTransition
in={sidebarClicked}
appear
timeout={1000}
classNames="drawer"
mountOnEnter
unmountOnExit
>
<div className="DevSearch__additional-search-criteria">
Additional Search Criteria
<div className="DevSearch__additional-search-criteria-individual">
<div
style={{
fontSize: '0.8rem',
marginBottom: '5px',
fontWeight: 'bold',
}}
>
Only show people who match more than {criteriaMatch}% of all
search criteria
</div>
<input
className="form-control"
type="number"
value={criteriaMatch}
onChange={(e) => setCriteriaMatch(e.target.value)}
min={0}
max={100}
step={5}
/>
</div>
</div>
</CSSTransition>
I also have a css file that is specifically for the CSS Transition component called DeveloperSearch.css:
.drawer-exit {
width: 250px;
}
.drawer-exit.drawer-exit-active {
width: 250px;
transition: width 1000ms ease-in;
}
.drawer-exit-done {
width: 0px;
}
.drawer-enter {
width: 250px;
}
.drawer-enter.drawer-enter-active {
width: 250px;
transition: all 1000ms ease-in;
}
Unfortunately, my results are no where near what I was wanting, as the drawer does not seem to slide out at all...
I also have replicated this issue in a codesandbox that can be found by clicking here. Thanks for your help!
Here is a pure css based solution but this is a bit hacky
Markup
const Drawer = ({ transitionExit, handleExit }) => (
<div
onClick={handleExit}
className={`drawer ${transitionExit ? "exit" : ""}`}
>
<p>Home</p>
<p>About</p>
<p>Contact</p>
<p>Close Drawer</p>
</div>
);
export default function App() {
const [isOpen, setIsOpen] = useState(false);
const [transitionExit, setTransitionExit] = useState(false);
const handleExit = () => {
setTransitionExit(true);
setTimeout(() => {
setIsOpen(false);
setTransitionExit(false);
// timeout should be less than animation time otherwise state might still be true
// after animation ends and drawer appears for few milliseconds
}, 450);
};
return (
<div className="App">
<div className="wrapper">
<div className="sidebar_container">
<button onClick={() => setIsOpen(true)}>open</button>
</div>
{isOpen && (
<div className={`container ${transitionExit ? "exit" : ""}`}>
<Drawer handleExit={handleExit} transitionExit={transitionExit} />
</div>
)}
</div>
</div>
);
}
CSS
.wrapper {
height: 90vh;
max-width: 60vw;
display: grid;
grid-template-columns: 30% 70%;
overflow: hidden;
margin: 40px;
}
.sidebar_container {
width: 100px;
height: 100%;
background-color: rgb(250, 207, 213);
padding: 30px;
position: relative;
z-index: 30;
}
#keyframes containerTransitionEnter {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#keyframes drawerTransitionEnter {
0% {
opacity: 0;
left: -10vw;
}
100% {
opacity: 1;
left: 0vw;
}
}
#keyframes containerTransitionExit {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes drawerTransitionExit {
0% {
opacity: 1;
left: 0vw;
}
100% {
opacity: 0;
left: -10vw;
}
}
.container {
position: relative;
z-index: 10;
height: 90vh;
animation: containerTransitionEnter 0.5s;
}
.drawer {
box-sizing: border-box;
position: relative;
height: 90vh;
width: 25vw;
padding: 20px;
background-color: rgb(4, 118, 156);
border-right: 1px solid rgba(0, 0, 0, 0.3);
animation: drawerTransitionEnter 0.5s;
}
p {
margin-bottom: 10px;
color: white;
}
.container.exit {
animation: containerTransitionExit 0.5s;
}
.drawer.exit {
animation: drawerTransitionExit 0.5s;
}
Here is the link to codesandbox
Since you are using react you can use Material UI for this Here
and you can try this in your case
<Drawer
className={classes.drawer}
variant=''
anchor='left'
open={open}
classes={{
paper: classes.drawerPaper,
}}>
<div className={classes.drawerHeader}>
<IconButton onClick={handleDrawerClose}>
{theme.direction === 'ltr' ? (
<ChevronLeftIcon />
) : (
<ChevronRightIcon />
)}
</IconButton>
</div>
<Divider />
<List>
{arr.map((text, index) => (
<ListItem
button
key={text}
onClick={
text === 'Home'
? goToHome
: text === 'About'
? handleOpenAbout
: text === 'Contact'
? goToContact
: text == 'Team'
? goToMyTea,
: goToDashboard
}>
<ListItemIcon>
{text === 'Home' ? (
<HomeIcon />
) : text === 'About' ? (
<NoteAddIcon />
) : text === 'About' || text === 'Contact' ? (
<ListAltIcon />
) : text === 'Dashboard' ? (
<DashboardIcon />
) : (
<></>
)}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</Drawer>
You should not delete div that has class="DevSearch__additional-search-criteria drawer-enter-done" from the DOM. In this case, Transition will not work. If you want to delete it, you must use css animation.
In this way, after adding div to the DOM, put animation on it to enter as a slider
here is a code example where i use Ref's to change style
import React, {useRef, useState, useEffect} from 'react'
import S from "./collapsible.module.css"
import PropTypes from 'prop-types'
import { faMinus, faPlus } from '#fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
function Collapsible(props) {
let myRef = useRef(null);
let buttonRef = useRef(null);
let [ button, setButton] = useState(true)
let Show = () => {
if(button) {
setButton(false)
buttonRef.current.style.backgroundColor = "#555"
myRef.current.style.maxHeight = myRef.current.scrollHeight + "px";
} else {
setButton(true)
buttonRef.current.style.backgroundColor = "hsl(181, 100%, 11%)"
myRef.current.style.maxHeight = "0px";
}
}
return (
<div
className={S.body}
>
<button
className={S.collapsible}
onClick={Show}
ref={buttonRef}
> {props.label}
<div className={S.icon}>
{button? <FontAwesomeIcon icon={faPlus} />:
<FontAwesomeIcon icon={faMinus} />}
</div>
</button>
<div
className={S.content}
ref={myRef}
>
<h3>{props.body}</h3>
</div>
</div>
)
}
Collapsible.propTypes = {
label: PropTypes.string,
body: PropTypes.string,
}
Collapsible.defaultProps = {
label: '',
body: "",
}
export default Collapsible
css:
.collapsible {
display: flex;
background-color: hsl(181, 100%, 11%);
color: white;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
outline: none;
font-size: 15px;
border-radius: 3px;
/* margin-bottom: 3px; */
box-shadow: 0px 1px 5px 1px black;
margin-top:13px;
}
.icon{
color:white;
position:absolute;
right:50px;
text-align:right;
justify-content: flex-end;
}
.active, .collapsible:hover {
background-color: #555;
}
.content {
padding: 0 18px;
max-height: 0px;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
This is just replicating this in React:
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_collapsible_animate
I have read that using Refs is bad, especially when using it to change the DOM, but if I didn't change the style with the exact amount shown in "scrollHeight" then the transition would be a messed up speed.
If there is another method Is this still bad practice?
It's more common practice to use a state value to determine the style like this:
<button
className={S.collapsible}
onClick={Show}
style={{backgroundColor: button ? "#555" : "hsl(181, 100%, 11%)"}
>
{props.label}
<div className={S.icon}>
{button ? (
<FontAwesomeIcon icon={faPlus} />
) : (
<FontAwesomeIcon icon={faMinus} />
)}
</div>
</button>
Or have a conditional className for your styles:
<button
className={`${S.collapsible} ${
button ? S.buttonColor : S.anotherButtonColor
}`}
onClick={Show}
>
{props.label}
<div className={S.icon}>
{button ? (
<FontAwesomeIcon icon={faPlus} />
) : (
<FontAwesomeIcon icon={faMinus} />
)}
</div>
</button>
and add .buttonColor and .anotherButtonColor to your CSS Module file (collapsible.module.css).
.buttonColor {
background-color: #555;
}
.anotherButtonColor {
background-color: hsl(181, 100%, 11%);
}
For the maxHeight on myRef, I'd do something like:
<div className={S.content} ref={myRef}>
<div style={{ maxHeight: myRef.current.scrollHeight }}>
<h3>{props.body}</h3>
</div>
</div>
In the case I have on toggle button that will bring this "mini drawer" that has some chips,
After pressing the Button
The issue in this case is that this chips just POP on the screen and I need to add some animation like this Drawer http://www.material-ui.com/#/components/drawer, I tried to add the transition and transform on CSS but It wont work
JS Part:
renderChip() {
console.log("1.30");
return this.state.listChip.map( (i, index) => (
<Chip className="chips">
{i.nome}
</Chip>
));
}
toggleList() {
this.setState({
visivel: !this.state.visivel,
});
// (this.state.visivel) ? document.getElementById("push").style.width = "0" : document.getElementById("push").style.width = "10px"};
}
render()
{
return (
<MuiThemeProvider>
<div >
<div className="anchor">
<RaisedButton
label="Label before"
labelPosition="before"
primary={true}
onClick = {this.toggleList}
/>
</div>
<div id="push" className="anchorz" style={(this.state.visivel) ? styles.wrapper : styles.closed} >
{this.renderChip()}
</div>
</div>
</MuiThemeProvider>
);
}
CSS part:
position: fixed;
display: flex;
right: 0;
bottom: 110px;
margin-right: 0;
margin-bottom: 0;
margin-left: 10px;
z-index: 900;
transition: transform 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;*/
overflow-x: hidden;
transition: 0.5s;