React Draggable stopping onClick for Child component - javascript

I am trying to create draggable cards that can also flip over on click.
This is my card
import { useState } from 'react'
import './Card.scss'
function Card() {
const [flip, setFlip] = useState(false)
return (
<div className={`card ${flip ? "flip" : ""}`}>
<div className="front" onClick={()=>{setFlip(!flip)}}>
<h1>Front</h1>
</div>
<div className="back" onClick={()=>{setFlip(!flip)}}>
<h1>Back</h1>
</div>
</div>
)
}
export default Card
This is the Draggable wrapper for the Card
import Draggable from 'react-draggable'
import Card from './Card'
function DraggableCard() {
return (
<Draggable>
<div>
<Card />
</div>
</Draggable>
)
}
export default DraggableCard
This is the CSS that is supposed to trigger onClick for the Card to flip
.card {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
border-radius: 20px;
transform: perspective(1000px) rotateY(var(--rotate-y, 0deg))
translate(var(--translate-y, 0))
rotate(var(--rotate, 0deg));
transition: transform 0.7s;
transform-style: preserve-3d;
cursor: pointer;
height: 300px;
width: 200px;
background-color: rgb(219, 14, 14);
}
.front {
position: absolute;
}
.back {
position: absolute;
transform: rotateY(180deg);
}
.front, .back {
height: 100%;
width: 100%;
backface-visibility: hidden;
transition: transform 1s;
}
.card.flip {
--rotate-y: -180deg;
}
The onClick handler in the Card should change the useState for "flip" and then, in turn, alter the className from "card" to "card flip" this should then trigger the CSS to flip the card. I can see that the className is not changing on click.
I saw that the Draggable README talked about using
Use an intermediate wrapper (<Draggable><span>...</span></Draggable>) in this case.
I added the extra <div> around the Card component in DraggableCard, but it did not seem to change the outcome. Did I miss understanding the README from react-draggable?
I assume that it is being overridden by the Draggable component but am struggling to figure out how not to let this happen.

Related

Block React Suspense to cover the whole page

I'm trying to use react lazy. I don't want the suspense to cover the page, but when it loads a component it shows the suspense blocked icon on the whole page.
How can I show it just where the component is supposed to be?
The lazy function:
const LandingPage = lazy(() =>
import('./auth/landing/landing').then(({ LandingPage }) => ({ default: LandingPage }))
);
<Suspense fallback={<Loader />}>
<LandingPage />
</Suspense>
The loader component:
import React from 'react';
import classnames from 'classnames';
import styled from 'styled-components';
// eslint-disable-next-line import/no-default-export
export default React.memo(styled(({ className }) => (
<div className={classnames('loader', className)}>
<span className="loader__ball loader__ball--1" />
<span className="loader__ball loader__ball--2" />
<span className="loader__ball loader__ball--3" />
</div>
))`
display: flex;
position: absolute;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
span.loader__ball {
display: inline-block;
margin: auto 0.25rem;
height: 0.75rem;
width: 0.75rem;
border-radius: 0.375rem;
background: #000000;
&.loader__ball--1,
&.loader__ball--2,
&.loader__ball--3 {
animation: bulging 2s infinite ease-in-out;
}
&.loader__ball--1 {
animation-delay: -0.4s;
}
&.loader__ball--2 {
animation-delay: -0.2s;
}
#keyframes bulging {
0%,
80%,
100% {
transform: scale(0);
opacity: 0.5;
}
40% {
transform: scale(1);
opacity: 1;
}
}
}
`);
thanks to anyone who will answer:)
This probably happens because of your CSS.
position: absolute;
width: 100%;
height: 100%;
If you don't have a container (where your Suspense is positioned in) with position: relative you will end up with a ball absolute positioned and stretched over your entire screen.
I put your snippet in a plain HTML/CSS fiddle, so you can see what to do:
https://jsfiddle.net/qLzcuo7h/
As you can see you would expect that your loader is within the both component boxes. But they aren't.
What you need to add is position: relative to the .component to make it work.
In you given code I can't see what element your parent is, since the Suspense is the outer element. I can't see where you will put that element.
The below fiddle is with the relative addition.
https://jsfiddle.net/qLzcuo7h/1/
Hope this will clear things up.

Why a few this same components works differently in react?

I have the following component named Card:
<article className={styles.card_container}>
<input type="checkbox" className={styles.checkbox} onClick={setCheckbox}/>
<div className={styles.text_container} id="txt_container">
<span>
{props.number}
</span>
</div>
</article>
Which should display checkbox, without the tick - container to check or not, with background colors, depends on this checkbox is checked or not.
For example, when unchecked this should has red color, but when checked - black.
For this, I decided to use state:
const [isChecked, setChecked] = useState(false);
const setCheckbox = (e) => {
if (isChecked===true){
setChecked(false);
document.getElementById("txt_container").style.backgroundColor="#a81616";
}else {
setChecked(true);
document.getElementById("txt_container").style.backgroundColor="#000";
}
}
I wanted to create a few this type of components so I decided to map this with information from array:
{data.map(element=>
<Card number={element.option} key={element.option}/>)
}
(Where data is an array with object with numbers, Card is created components with code above).
The problem is that, when I "check" other components, it change color only at first.
Why did it happen? I appreciate for any help.
And there some css code:
.card_container {
position: relative;
width: 60px;
height: 45px;
margin: 5px;
float: left;
border: 2px solid #50bcf2;
box-sizing: border-box;
}
.text_container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
line-height: 25px;
transition: .5s ease;
}
.checkbox {
position: absolute;
top: 0;
left: 0;
width: 60px;
height: 45px;
opacity: 1;
cursor: pointer;
}
I would like to do this by js, is there other way to do this (not by css)? Or maybe can I inject background color provided by props from for example an array to Card component?
You can use style attribute on react component
<div className={styles.text_container} style={{backgroundColor: isChecked? #a81616 : #000}}>
your code doesnt work, because ID is supposed to be unique and you are only selecting first occurence... if you want to work with DOM in react, dont use getElementByID and use useRef() from react. Its more "reactish" way how to do it.

CSS rotate transform messes up hover on sibling element

Im trying to implement an overlay on an image element, with a button inside that lets you rotate the image 180 degrees. This works fine until you rotate the image the first time, then the overlay will not show up again or is for some reason behind the image tag, i have tried setting the z-index of the image to -999 but that did not do anything. I need the solution to work on mobile to, so working with onmouseover event listeners wasnt an option for me.
Code Sandbox here
Code:
<div class="relative">
<div class="absolute overlay">
<button id="rotate">Click to Rotate this Image 180 Degrees</button>
</div>
<div>
<img id="image-to-rotate" src="https://picsum.photos/200/300" />
</div>
</div>
import "./styles.css";
document.getElementById("rotate").addEventListener("click", () => {
document.getElementById("image-to-rotate").classList.toggle("rotate");
});
.relative {
position: relative;
height: 300px;
width: 200px;
}
.absolute {
color: white;
position: absolute;
background-color: rgba(0, 0, 0, 0.6);
height: 100%;
width: 100%;
/*invisible by default*/
opacity: 0;
}
.absolute:hover,
.absolute:active {
/*show on hover, also on activate to work on mobile*/
opacity: 1;
}
.rotate {
transform: rotate(180deg);
}
.absolute:hover,
.absolute:active,
.absolute:visited {
/*show on hover*/
opacity: 1;
z-index: 999;
}
I added the visited to your css and the z-index and it stays after you click.

React/Redux/CSS - Modal placement

i have a Card and a Modal component like so
class Card extends Component {
constructor() {
super();
this.state = { showModal: false }
}
render() {
const { showModal } = this.state;
return (
{/* Some code */}
{showModal && <Modal />}
)
}
}
So, I don't want to render my Modal until it is required. Logic.
The Modal's job, in this context, is to display the full content of the Card component (The Card has a fixed height, so I cannot displaying every bit of information in there).
Now, at a higher level I have the following:
class App extends Component {
/* Some Code */
render() {
return (
<div>
<Content /> {/* Our content */}
<Overlay /> {/* Our all-purpose-overlay (we need it for the Modal) */}
</div>
)
}
}
The problem is that my Card component has the style position: relative and the Modal component has the a z-index and the style position: absolute.
I did some research and I read that nested elements with non-static
position will not work the same way regarding the z-index. The z-index will take effect only within the non-static element.
So I cannot make my Modal appear above the the Overlay component. Furthermore, The Card component has a overflow:hidden property. And so, the Modal gets cropped.
Here is a simple demonstration.
function toggleModal() {
var app = document.getElementById("app");
app.classList.toggle("-modal");
}
:root {
background: #ddd;
}
#app,
#overlay {
height:100vh;
width:100%;
}
#app {
display: flex;
align-items: center;
justify-content: center;
}
/* Overlay */
#overlay {
position: absolute;
top: 0;
left: 0;
z-index: 1;
visibility: hidden;
background: rgba(0,0,0,0.3);
}
.-modal #overlay {
visibility: visible !important;
}
/* Card */
#card {
position: relative;
width: 250px;
padding: 1em;
border-radius: 5px;
background: white;
overflow: hidden; /* Problem */
}
.content {
padding: 4em 0;
text-align: center;
}
.btn {
padding: 1em 2em;
border:none;
color:white;
float: right;
cursor: pointer;
transition: 0.2s ease;
background: #00abff;
}
.btn:hover {
background: #0c9de4;
}
/* Modal */
#modal {
width: 300px;
position: absolute;
top:0;
left: 50px; /* Modal Gets clipped */
visibility: hidden;
background-color:red;
}
.-modal #modal {
visibility: visible;
}
<div id="app">
<div id="card">
<div class="content">content</div>
<button class="btn" onclick="toggleModal()">Display Modal</button>
<div id="modal">
<div class="content">
<div>Modal</div>
<div>With same content</div>
<div>(under the Overlay and also cropped)</div>
</div>
</div>
</div>
<div id="overlay" onclick="toggleModal()"></div>
</div>
Question : How should I organize my components so that I do not get this problem?
I thought of having only one Modal at top level. Then I simply display it. But I need to render the children of the Card into the Modal.
How should I proceed?
Since you are using React, what I would actually recommend is to use a Portal to render your modal. One thing Portals solve in React are precisely this issue. If you are using a more recent version of React (16+) then you already have access to portals.
If you are using an older version of React, that is okay. You can use an implementation like this (react-portal) instead.
Now you will have your components/markup rendered in a totally separate React tree outside of the context of your containing <div> that has position: relative on it and you can absolute or fixed position it wherever you need to.

React and Flex layout how to use them

I am trying to use React and flexbox.Normally i can use flexbox at react native but icouldnt achive in react.js
this is my Css file
.wrapper, html, body {
height:100%;
margin:0;
position:absolute;
}
.wrapper {
display: flex;
flex-direction: column;
}
.nav {
background-color: red;
flex:1
}
.main {
background-color: blue;
flex:1
}
This is my js file
import React, { Component } from 'react';
import './background.css';
import { Icon } from 'semantic-ui-react'
import Navbar from './navbar'
class Back extends Component {
render() {
return (
<div className="wrapper">
<div className="nav"></div>
<div className="main"></div>
</div>
);
}
}
export default Back;
I got just a white screen what might be a problem ?
Thank you
As the wrapper is positioned absolute, and have no content to grow with, its width collapse to 0.
So simply remove position: absolute from the .wrapper, html, body rule.
If you still want to use position: absolute, you need to also give the wrapper a width.
.wrapper,
html,
body {
height: 100%;
margin: 0;
}
.wrapper {
display: flex;
flex-direction: column;
}
.nav {
background-color: red;
flex: 1
}
.main {
background-color: blue;
flex: 1
}
<div class="wrapper">
<div class="nav"></div>
<div class="main"></div>
</div>
You can also use float:left in the wrapper class.

Categories