React - mousemove event isn't working correctly - reactjs

I'm creating a range slider and this is how it works: i've added onMouseDown event to the slider - in the function, i've attached onMouseMove and onMouseUp events to document - that's it! Simple. It works perfect on codepen.io but not locally.
I expected to see the log "down" in the console, then a lot of "move" and finally get the "up" message.
But the events showing up at the same time after release the mouse button.
console log:
Where could be the problem? How to fix if?
My project is created with create-react-app. I ran it in Google Chrome and Opera.
That's my code:
class Box extends React.Component {
downHandler = (e) => {
console.log('down');
document.addEventListener('mousemove', this.moveHandler);
document.addEventListener('mouseup', this.upHandler);
}
moveHandler = (e) => {
console.log('move');
}
upHandler = (e) => {
console.log('up');
document.removeEventListener('mousemove', this.moveHandler);
document.removeEventListener('mouseup', this.upHandler);
}
render() {
return (
<div className="container">
<div className="circle"
onMouseDown={this.downHandler}></div>
</div>
)
}
}
ReactDOM.render(<Box />, document.getElementById('root'));
.container{
width: 400px;
height: 7px;
background-color: #abc4f1;
position: relative;
margin-top: 120px;
}
.circle{
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #eee;
box-shadow: 0 0 2px 2px rgba(0, 0, 0, .2);
position: absolute;
top: -7px;
left: calc(50% - 10px);
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Related

Is there a way to fill up the delay of useState?

I'm new to React and I'm trying to make a simple animation, but when the animation ends there is literally a split second that is showing the old values of opacitate & translate.Is there a way that i can make that dissapper?
I've tried to use useRef and re-render the component but no luck.Ignore the timeout functionz
const { useEffect, useState } = React;
const Titlu = () => {
let [opacitate, setOpacitate] = useState(0);
let [translate, setTranslate] = useState(-30);
function Schimba() {
setOpacitate(prevOpacity => prevOpacity = 1);
setTranslate(prevTranslate => prevTranslate = 20);
}
function timeout(timp) {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
})
}
return (
<div className="Part1">
<h1 className="ForkyTitlu"
onAnimationEnd={Schimba}
style={{
opacity:opacitate,
transform: `translate(${translate}%, 0%)`
}} >
<span className ="Forky">Forky</span>
<span className ="Nutrition">Nutrition</span>
</h1>
</div>
);
}
ReactDOM
.createRoot(root)
.render(<Titlu />);
.Part1 {
display: inline-flex;
margin-bottom: 50vh;
border-bottom: 3px black;
}
.ForkyTitlu {
color: orange;
font-size: 3vw;
/*
margin-left: 12vw;
margin-top: 40vh;
transform: translateX(-50%);
*/
animation-name: titluAnimation;
animation-delay: 1s;
animation-duration: 2s;
animation-iteration-count: 1;
position: relative;
}
#keyframes titluAnimation {
100% {
opacity: 1;
transform: translateX(20%);
}
}
.Forky {
color: black;
font-size: 9vw;
text-shadow: -30px 15px 30px #0000009c;
}
.Nutrition {
color: orange;
font-size: 3.5vw;
text-shadow: -30px 15px 30px orange;
}
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="root"></div>
When onAnimationEnd calls Schimba, the animation is over, and the CSS values are resettled top their original values. This is the gap you're seeing.
However, you don't really need a state. Move all animation related properties, including the initial state to the animation:
#keyframes titluAnimation {
from {
opacity: 0;
transform: translateX(-30%);
}
to {
opacity: 1;
transform: translateX(20%);
}
}
And define the animation-fill-mode (I've used the animation shorthand) to be forwards:
animation: titluAnimation 2s forwards;
forwards
The target will retain the computed values set by the last keyframe encountered during execution.
const Titlu = () => (
<div className = "Part1">
<h1 className = "ForkyTitlu">
<span className ="Forky">Forky</span>
<span className ="Nutrition">Nutrition</span>
</h1>
</div>
);
ReactDOM
.createRoot(root)
.render(<Titlu />);
.Part1 {
display: inline-flex;
margin-bottom: 50vh;
border-bottom: 3px black;
}
.ForkyTitlu {
color: orange;
font-size: 3vw;
animation: titluAnimation 2s forwards;
position: relative;
}
#keyframes titluAnimation {
from {
opacity: 0;
transform: translateX(-30%);
}
to {
opacity: 1;
transform: translateX(20%);
}
}
.Forky {
color: black;
font-size: 9vw;
text-shadow: -30px 15px 30px #0000009c;
}
.Nutrition {
color: orange;
font-size: 3.5vw;
text-shadow: -30px 15px 30px orange;
}
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="root"></div>
If you want/need to use state to control the animation, it's better to define the start/end states as classes, toggle them with the state, and use CSS transition to animate the change.
Example - click the Toggle button to see the animation:
const { useState } = React;
const Titlu = () => {
const [start, setState] = useState(true);
const toggleStart = () => setState(s => !s);
return (
<div>
<div className = "Part1">
<h1 className = {`ForkyTitlu ${start ? 'start' : 'end'}`}>
<span className ="Forky">Forky</span>
<span className ="Nutrition">Nutrition</span>
</h1>
</div>
<button onClick={toggleStart}>Toggle</button>
</div>
);
};
ReactDOM
.createRoot(root)
.render(<Titlu />);
.Part1 {
display: flex;
border-bottom: 3px black;
}
.ForkyTitlu {
color: orange;
font-size: 3vw;
position: relative;
transition: all 2s;
}
.ForkyTitlu.start {
opacity: 0;
transform: translateX(-30%);
}
.ForkyTitlu.end {
opacity: 1;
transform: translateX(20%);
}
.Forky {
color: black;
font-size: 9vw;
text-shadow: -30px 15px 30px #0000009c;
}
.Nutrition {
color: orange;
font-size: 3.5vw;
text-shadow: -30px 15px 30px orange;
}
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="root"></div>

ReactDOM.createPortal modal is mounted on DOM but nothing is displayed on the screen

this is a typescript-next.js project. I have this Modal component:
interface ModalProps {
onCancelModal: () => void;
onAcceptModal: () => void;
acceptEnabled: boolean;
isLoading?: boolean;
title: string;
}
const Modal: React.FC<ModalProps> = (props) => {
let containerRef = useRef<HTMLDivElement | null>(null);
console.log("container", containerRef);
useEffect(() => {
const rootContainer = document.createElement("div");
const parentElem = document.querySelector("#__next");
parentElem?.insertAdjacentElement("afterend", rootContainer);
if (!containerRef.current) {
containerRef.current = rootContainer;
}
return () => rootContainer.remove();
}, []);
return containerRef.current
? ReactDOM.createPortal(
<div className="modal">
<header className="modal__header">
<h1>{props.title}</h1>
</header>
<div className="modal__content">{props.children}</div>
<div className="modal__actions">
<Button design="danger" mode="flat" onClick={props.onCancelModal}>
Cancel
</Button>
<Button
mode="raised"
onClick={props.onAcceptModal}
disabled={!props.acceptEnabled}
loading={props.isLoading}
>
Accept
</Button>
</div>
</div>,
containerRef.current
)
: null;
};
export default Modal;
I pass a custom error to ErrorHandler component:
const ErrorHandler: React.FC<ErrorHandlerProps> = (props) => (
<Fragment>
{props.error && <Backdrop onClick={props.onHandle} />}
{props.error && (
<Modal
title="An Error Occurred"
onCancelModal={props.onHandle}
onAcceptModal={props.onHandle}
acceptEnabled
>
<p>{props.error}</p>
</Modal>
)}
</Fragment>
);
However, Modal component is successfully mounted on the DOM but nothing displays on the screen.
EDIT
I have backdrop and modal components.
// css for backdrop
.backdrop {
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, 0.75);
z-index: 100;
position: fixed;
left: 0;
top: 0;
transition: opacity 0.3s ease-out;
opacity: 1;
}
// css for Modal
.modal {
position: fixed;
width: 90%;
left: 5%;
top: 20vh;
background: white;
border-radius: 5px;
z-index: 200;// I changed this to 999999 but didnot solve the issue
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
}
.modal__header {
border-bottom: 2px solid #3b0062;
}
.modal__header h1 {
font-size: 1.5rem;
color: #3b0062;
margin: 1rem;
}
.modal__content {
padding: 1rem;
}
.modal__actions {
padding: 1rem;
text-align: right;
}
.modal__actions button {
margin: 0 0.5rem;
}
#media (min-width: 768px) {
.modal {
width: 40rem;
left: calc((100% - 40rem) / 2);
}
}
I found the answer after i refresh my memory. I realized that there is another .modal className on elements-styles tab. It points me to the /node_modules/bootstrap/scss/_modal.scss file which also has modal className and it was overriding my custom className.
.modal {
position: fixed;
top: 0;
left: 0;
z-index: $zindex-modal;
display: none;
width: 100%;
height: 100%;
overflow: hidden;
// Prevent Chrome on Windows from adding a focus outline. For details, see
// https://github.com/twbs/bootstrap/pull/10951.
outline: 0;
// We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a
// gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342
// See also https://github.com/twbs/bootstrap/issues/17695
}

Design Bootstrap dynamic nav tabs component

I want to design a dynamic nav tabs component. when the card is clicked relevant tab is shown, with the connection arrow and border-color green.
sample code or a suggestion would be much helpful
.
You can use accordion by bootstrap. Use css flexbox to horizontally align the tabs next to each other and bind a javascript method that changes css color properties (arrow, green color) on clicking.
Here is the link - https://getbootstrap.com/docs/4.0/components/collapse/
Here is how you can do :
.js :
import React, { Component } from "react";
import { render } from "react-dom";
import "./style.css";
const App = () => {
const selectBlock = (e) => {
e.target.classList.toggle('selected');
}
return (
<div className="block" onClick={(e) => {selectBlock(e)}}>
<div>Here is the block</div>
<div className="arrow">
<FakeArrow />
</div>
</div>
);
};
const FakeArrow = () => {
return (
<div>
<span className="arrow-down-border" />
<span className="arrow-down" />
</div>
);
};
render(<App />, document.getElementById("root"));
.css :
.block {
position: relative;
width: 150px;
height: 50px;
text-align: center;
border: 2px solid black;
}
.arrow {
display: none;
}
.block.selected {
border: 2px solid #99d32c;
}
.block.selected .arrow {
display: block;
}
/* You need to fake the arrow border with another arrow behind */
.arrow-down-border {
position: absolute;
bottom: -20px;
left: 55px; /* 150px (main block) / 2 -20px (size of the triangle)*/
width: 0;
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-top: 20px solid #99d32c;
}
.arrow-down{
position: absolute;
bottom: -17px;
left: 58px; /* 150px (main block) / 2 -17px (size of the triangle)*/
width: 0;
height: 0;
border-left: 17px solid transparent;
border-right: 17px solid transparent;
border-top: 17px solid #ffffff;
}
Here is the repro on Stackblitz.
Of course this is just an example, you have to set a color for the arrows so my advice would be to do it with constants or props. Same thing for the position and others functionality you can add to the FakeArrow component.
Now, it would be waaaayy easier to manage it with an image if you really need a border (this is the tricky part in your requirement), or a simple arrow without border.
You can take a look at this post, it's the same question actually, i used a slightly different way to do it with css, but the result seems to be the same.

react Semantic-UI - multi-select checkbox drop-down

i want to built an multi select checkbox dropdown in react with es6
my requirement is as below specified in image
I tried doing this click here but it is not working.
You can use one parent component that will keep values in its state and toggle list items. Then you can create component for each list item that will keep active property in state that you can toggle on click.
class ListItem extends React.Component {
constructor(props) {
super(props);
this.state = {active: false}
}
render() {
return (
<a
onClick={() => {
this.setState(prevState => {
let newState = !prevState.active;
this.props.handleClick(newState, this.props.value);
return {active: newState}
})
}}
className={!this.state.active ? '' : 'selected'}
href="#">
{this.props.value}</a>
)
}
}
class Select extends React.Component {
constructor(props) {
super(props);
this.state = {
showList: false,
value: []
}
this.handleItemClick = this.handleItemClick.bind(this)
}
componentDidMount() {
document.addEventListener('mousedown', (e) => {
if(!this.node.contains(e.target)) {
this.setState({showList: false})
}
})
}
componentWillUnmount() {
document.removeEventListener('mousedown');
}
renderValue() {
let {value} = this.state;
if(!value.length) return "Select..."
else return value.join(', ')
}
toggleList() {
this.setState(prevState => ({showList: !prevState.showList}))
}
handleItemClick(active, val) {
let {value} = this.state;
if(active) value = [...value, val]
else value = value.filter(e => e != val);
this.setState({value})
}
render() {
return (
<div
ref={node => this.node = node}
className="select">
<button onClick={this.toggleList.bind(this)}>
<span className="select_value">
{this.renderValue()}
</span>
</button>
<div
className={"select_list " + (!this.state.showList && 'hide')}>
<ListItem handleClick={this.handleItemClick} value="Lorem" />
<ListItem handleClick={this.handleItemClick} value="Ipsum" />
<ListItem handleClick={this.handleItemClick} value="Dolor" />
</div>
</div>
)
}
}
ReactDOM.render(
<Select />,
document.getElementById('container')
);
button {
background: white;
width: 100%;
padding: 10px 15px;
border: 1px solid rgba(0, 0, 0, .1);
border-radius: 5px;
cursor: pointer;
text-align: left;
}
.select_list {
width: 100%;
background: white;
border: 1px solid rgba(0, 0, 0, .1);
border-radius: 5px;
}
.select_list a {
padding: 10px 15px;
display: flex;
color: black;
text-decoration: none;
position: relative;
align-items: center;
}
.select_list a:before {
width: 15px;
height: 15px;
content: '';
border: 1px solid rgba(0, 0, 0, .1);
border-radius: 5px;
margin-right: 10px;
display: block;
}
.select_list a.selected:before {
background: #0493D1;
content: '✓';
color: white;
font-size: 11px;
text-align: center;
line-height: 15px;
}
.hide {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
Semantic-UI React Approach
After much digging, I found an old conversation between eugenetumachov and Semantic-UI developers(?). One of the users provided incredibly helpful code that answers this question using Semantic-UI's Dropdown component.
This is done by making use of Dropdown's Dropdown.Menu and Dropdown.Item. Then looping through your options via map to create checkboxes. The only downside is that the workaround does not seem to allow scrolling and will require more CSS. Additionally, based on CSS the checkbox items' background color may turn transparent if you double-click on the dropdown, and the dropdown will collapse on mouse hover. You can bypass the transparency issue by using a class or style property for your Dropdown.Menu and Dropdown.Item.
Semantic-UI developer's response to this type of question appears to be a flat "no" or a
Active items are automatically removed from the Dropdown menu. So you cannot show a "checked" state for an item in the menu.
You could create a similar component out of an Input as a trigger for
a Popup containing a Menu or List of Checkboxes.
Are dropdowns with checkboxes possible? #2417
eugenetumachov's workaround

react-modal is rendered at bottom of the screen

I'm using react-modal in my app, but I can't easily get it to render on top of the current screen content. The modal always renders at the bottom of the screen (below the html body even).
This is my custom modal:
import Modal from 'react-modal';
var SimpleModal = React.createClass({
render() {
return (
<Modal
isOpen={this.props.isOpen}
className="modal-content"
contentLabel="modal"
onRequestClose={this.props.onClose} >
<h1 className="modal-header">{this.props.title}</h1>
<div className="modal-body">
<p>{this.props.message}</p>
</div>
<Button bsStyle={this.props.type} className="modal-button" onClick={this.props.closeModal}>Close</Button>
</Modal>
)
}
});
const mapStateToProps = (state) => {
return {
isOpen: state.modals.notification.isOpen,
type: state.modals.notification.type,
title: state.modals.notification.title,
message: state.modals.notification.message,
}
};
const mapDispatchToProps = (dispatch) => {
return {
closeModal: () => dispatch(skjeraActionCreators.closeNotificationModal()),
}
};
export default connect(mapStateToProps, mapDispatchToProps)(SimpleModal)
The SimpleModal component is included in the render function of my top level container (AppContainer), like this:
render() {
return (
<div>
<SimpleModal />
<App
onLogout={this.logout}
isLoggedIn={this.props.isLoggedIn}
username={this.props.username}
subpages={this.props.children}
/>
</div>
)
}
Note that I haven't tweaked the style/css, so it uses the default styling, and thus the default positioning scheme.
Can anyone help me out tracking down this bug? Any help will be appreciated.
EDIT: This is the CSS entries (probably some redudant elements there) I've referred to in my code:
.modal-header {
background-color: inherit;
border: none;
}
.modal-body {
padding-top: 10px;
padding-bottom: 10px;
}
.modal-button {
padding-left: 10%;
margin-left: 20px;
}
.modal-content {
position: absolute;
background-color: white;
color: black;
top: auto;
bottom: auto;
overflow: auto;
right: auto;
left: 10px;
border-radius: 20px;
outline: none;
border: solid;
border-width: medium;
border-color: black;
padding-bottom: 10px;
}

Resources