I have a React Component with an absolute positioned div which overlays other content in my application. The div is used to fire react's onMouseMove event.
I want to set the css value pointer-events-none so all components underneath the div are still clickable, have pointer events etc. Whatever when pointer-events-none is present, the onMouseMove event will not fire anymore. Everything should behave like the overlay div is not present, it should just fire onMouseMove.
The code structure looks like this:
<button>I should be clickable</button>
<div>
<div
style={{
opacity: 0,
position: `absolute`,
top: `50px`,
left: `50px`,
width: `30vw`,
height: `30vh`,
pointerEvents: `none`,
}}
onMouseMove={() => {
console.log(`Fire!`)
}}
>
Overlay
</div>
<button>I should be clickable</button>
<a>I should be clickabel</a>
</div>
<button>I should be clickable</button>
I think I'm missing something or have chosen a completely wrong path here.
Thanks a lot for your help!
You need to place overlay div at the root (in such case events will propagate), remove pointerEvents rule and opacity so that the content inside div would be visible:
<div
style={{
position: `absolute`,
top: `50px`,
left: `50px`,
width: `30vw`,
height: `30vh`
}}
onMouseMove={() => {
console.log(`Fire!`)
}}
>
<button>I should be clickable</button>
<button>I should be clickable</button>
<a>I should be clickable</a>
<button>I should be clickable</button>
</div>
Related
I have JSX code like this:
<div id="parent" onClick={clickOnParent} style={{ width: 100, height: 100 }}>
<div id="child" onClick={clickOnChild} style={{ width: 20, height: 20 }} />
</div>
When I click on parent (outside the child) it will run clickOnParent, and when I click the child it will run both clickOnParent and clickOnChild of course.Now I want to trigger only clickOnChild and ignore clickOnParent when clicking exactly on the child. How can I do?
Use Event.stopPropagation()
const clickOnChild = (event) => {
event.stopPropagation();
...
}
In my react app I have a hidden banner that I want to show, when the length of the array reaches to 5. But it looks like that I am trying to get an element before it is rendered. I get the error about getting a style of undefined element.
This function must change css of the banner element and make it visible.
showBanner() {
let banner = document.getElementsByClassName('overlay')[0]
banner.style.cssText = "visibility: visible;opacity: 1;"
}
I want to render my popup component only if the condition is met.
render() {
if (this.props.awarded) {
if (this.props.awarded.length === 5) {
this.showBanner()
return (
<>
<h1 id="awardLabel">5 movies</h1>
<div id="movieList">
{this.props.awarded.map((movie) => {
return (
<div className="awardHolder" key={movie.imdbID}>
<div className="awardImgHolder" >
<img src={movie.Poster} alt={movie.Title}></img>
</div>
<div className="awardMovieInfo">
<p>{movie.Title}</p>
<p>year {movie.Year}</p>
</div>
<div className="withdrawButton" onClick={(e) => this.deleteMovie(e, movie)}> WITHDRAW </div>
</div>
)
})}
</div>
<Popup />
</>
)
} else { ...
This is my banner structure.
<div id="popup1" className="overlay">
<div className="popup">
<h2>Here i am</h2>
<a className="close" href="#">×</a>
<div className="content">
<p>Congratulations. You've nominated 5 movies.</p>
<button onClick={this.closeBanner}>Try again</button>
</div>
</div>
</div>
This is my css for the banner element.
.overlay {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.7);
transition: opacity 500ms;
visibility: hidden;
opacity: 0;
}
How can I dynamically change element's styles using conditions to render that element?
You're trying to access your Popup component before it gets created. In other words, this.showBanner() is called before <Popup /> is rendered.
One solution is to move your popup to a higher-level component
This might be a good use case for React Context, which will allow you to have some global state that your components can tap into without having to pass the banner state through multiple components as props.
If you are going to do this, you might consider not manually updating the styling with querySelectors; instead, you can have React either render or not render the component based on your global banner state.
Your application will be wrapped in <BannerContext.Provider> tags, and then the component that needs to render or not render the banner can use <BannerContext.Consumer> tags to check the current banner state. You can also store a toggle function in the BannerContext so that other parts of the application (and the banner itself) can toggle the BannerContext as needed.
I have a react-table component with custom column header
const popupRef = createRef();
const column = [{
Header: () =>
<div ref={popupRef} className="eye-icon">
<img src={icon}/>
</div>
fixed: "left",
sortable: false,
headerClassName: "table-header-class",
className: "table-row-class",
width: 70
}];
And I have a reactjs-popup that I want to be triggered after I press on that component.
return (
<div>
<Popup
className="popup"
closeOnDocumentClick
trigger={popupRef.current}
arrow={true}
repositionOnResize={true}
on="click"
position="bottom left"
>
<div className="popup">
<span>popup</span>
</div>
</Popup>
<div className="table">
<ReactTableFixedColumns
showPagination={false}
defaultPageSize={selectedTestsLength}
data={data}
style={{height: "73vh"}}
columns={column}
/>
</div>
</div>
);
It doesn't work.
Of course I can make onClick event in header's div to forcly open the popup with reactjs-popup open property - but it appears on the center of the screen and it looks like modal, so this approach is not suitable, I want it to stick to the div, to be placed in correct place.
I think you are using the wrong approach here. Refs are not needed to achieve what you want.
Just simply declare the Popup inline inside the header:
const column = [{
Header: () =>
<Popup trigger={
<div ref={popupRef} className="eye-icon">
<img src={icon}/>
</div>
}>
<div className="popup">
<span>popup</span>
</div>
</Popup>
fixed: "left",
sortable: false,
headerClassName: "table-header-class",
className: "table-row-class",
width: 70
}];
I don't have access to your full code so I can't tell for sure but that should give you the idea.
I just did an empty div and put trigger in it
trigger={<div className="sample-trigger"></div>}
.sample-trigger {
width: 1px;
height: 1px;
display: block;
visibility: hidden;
}
In the main div I am using to trigger the popup I set the onClick to change the state of {wasPopupOpen}
<Popup
className="popup"
closeOnDocumentClick
open={wasEyePopupOpen}...
I also make some adjustmenst on popup window so it looks like inside of that div.
I am looking for an easy way of allow a user to resize a div using handles and all relevant cursors. I see lots of examples using jquery but I would like to use it in react and jquery isn't required.
Does anyone know a easy way of doing this ? I presume pure js, css. I don't really want to use a react component for this, as I need to enable resizing on standard divs.
Of course it is for use with reactjs, is there a more modern way of doing this without jquery ?
** EDIT **
These are the cursors that could be used for each resizable point
e-resize ne-resize n-resize nw-resize s-resize se-resize
w-resize sw-resize
You can only with CSS, resize property allows you to make that!
.resize {
border: 1px solid black;
overflow:auto;
}
.resize.horizontal {
resize: horizontal;
}
.resize.vertical {
resize: vertical;
}
.resize.both {
resize: both;
}
.wrap {
max-width: 80%;
}
<div class="wrap">
<div class="resize horizontal">Resize me!</div>
<div class="resize vertical">Resize me!</div>
<div class="resize both">Resize me!</div>
</div>
Requirements
overflow different than visible (initial) is required and you can apply it to all elements whos overflow is setted with auto, scroll and hidden.
I call this property marvellous!
Heres an example of a great solution using react-resize-panel library
https://www.npmjs.com/package/react-resize-panel
Put anything you want to show inside the divs, you can customize the handler too.
import ResizePanel from "react-resize-panel";
...
<div style={{
width: '80%',
height: '500px',
border: '1px solid black',
display: 'flex',
flexDirection: 'column'}}>
<ResizePanel direction='s' style={{backgroundColor: 'black', height: '50%'}}>
<div style={{backgroundColor: 'orange', height: '100%'}}>panel</div>
</ResizePanel>
<div style={{backgroundColor: 'purple', flexGrow: '1'}}>panel</div>
</div>
...
Hope this can help someone else
A few days ago I wanted to build something like this but with 2 div elements.
using resize property from css made it's width 0 when there are multiple elements so I tried javascript.
I saw an example using onMouseMove event but there are many problems with this example so I made a new sandbox in which I use the onDarg event.
Here is the important code:
const dragHandler = useCallback(
(e) => {
const w =
((e.clientX -
e.currentTarget.parentElement.parentElement.getBoundingClientRect()
.left) /
e.currentTarget.parentElement.parentElement.getBoundingClientRect()
.width) *
100;
if (w > 0 && w !== width) {
setWidth(w);
}
},
[width]
);
and
<Box width={width} />
<div
draggable
onDrag={dragHandler}
className="flex justify-center items-center p-1 h-full bg-slate-800 cursor-col-resize"
>
<div className="w-1 border-x border-white h-1/6" />
</div>
<Box width={100 - width} />
Hope it helps \(^_^)/
This is what I have so far:
<div style = "position: relative;">
<a href = "#games">
<div class="sidenavOff">
<img src = "images/card_normal.png" />
<img src = "images/category_icons/icon_games.png" style = "position: absolute; top: 10px; left: 40px;" />
<img src = "images/category_titles/title_games.png" style = "position: absolute; top: 160px; left: 40px;" />
</div>
<div class = "sidenavOver">
<img src = "images/hover/card_hover.png" />
<img src = "images/category_titles/title_games.png" style = "position: absolute; top: 10px; left: 40px;" />
<img src = "images/hover/card_hover_separator.png" style = "position: absolute; top: 40px; left: 40px;" />
Show a bunch of text here
<img src = "images/button_start_normal.png" style = "position: absolute; top: 200px; left: 40px;" />
/div>
</a>
</div>
So card.png is a notecard that has multiple transparent images overlayed on top of it. When the mouse is away from the card, it has icon_games.png and title_games.png showing on the card. I want it so that when the mouse hovers over card.png, icon_games.png, or title_games.png (in other words, whenever the mouse pointer is in the card), the card displays the elements title_games.png, card_hover_separator.png, a text description, and button_start_normal.png, in that order vertically (and the positioning of this should be editable as it will likely be different than the images displayed when not hovering).
This is my jquery code (I've never used it before so I'm pretty sure this is off. I don't quite understand it):
$(document).ready(function() {
$(“div.sidenavOff”).mouseover(function(){
$(this).removeClass().addClass(“sidenavOver”);
}).mouseout(function(){
$(this).removeClass().addClass(“sidenavOff”);
});
});
In a more understandable format, without hover:
http://img834.imageshack.us/img834/7026/screenshot20130606at122.png
With hover:
http://imageshack.us/photo/my-images/855/screenshot20130606at122.png/
This is my jquery code [...]. I don't quite understand it
$(document).ready(function () {/* function body */});
When document (as a jQuery object $) is ready, invoke a function as described by /* function body */
$("div.sidenavOff")
Use jQuery $ to get all HTMLElements that match the CSS Selector div.sidenavOff
.mouseover(function () {
$(this).removeClass().addClass("sidenavOver");
})
When the mouse goes over one of these elements (mouseover), remove the class undefined (as nothing between brackets, removeClass), then add the class sidenavOver (addClass) to the element that the mouse is over (this). class here can be understood as meaning the same as the HTML attribute class; <a class="xyz">
.mouseout(function () {
$(this).removeClass().addClass("sidenavOff");
})
When the mouse leaves one of these elements (mouseout), similar to when it goes over them, except this time adding the class sidenavOff to that element.
You're close but probably want code that looks like this
$(document).ready(function () {
$("div.sidenavOff").mouseover(function () { // add visibility flag
$("div.sidenavOver").addClass("showme"); // to div.sidenavOver
}).mouseout(function () { // remove visibility flag
$("div.sidenavOver").removeClass("showme"); // from div.sidenavOver
});
});
Where the class showme relates to some CSS to force the element to be displayed
.showme {display: block;}
It sounds like you are just trying to show or hide the "sidenavOver" div when the mouse hovers the container. Is that correct?
I created this jsfiddle using your html, but commented out all your missing images and added a class to your container div.
http://jsfiddle.net/joshvito/GaZQ6/
e.g.
//on hover over the container; you can use the a tag too, which ever element you want to bind the event to
$('.container').on({
mouseenter: function () {
$(".sidenavOff").hide(); //On mouseover, hode the first div
$(".sidenavOver").show();
},
mouseleave: function () {
$(".sidenavOff").show();
$(".sidenavOver").hide();
}
});
good reference for the js event handlers is at JQUERY API Documentation for .on