How to disable click events for props.children in React? - reactjs

How can any click events be disabled for props.children?
const Example = props => (
<div>
<div>This can be clicked</div>
{props.children} /* These can't be clicked */
</div>
)
I am rendering a PDF page using react-pdf and want the user to be able to drag a custom selection marquee (like in Photoshop...). As it is, the PDF page under or inside the marquee element still registers mouse events upon dragging, like text selection.

There is an easy, but not robust way to do this:
const Example = props => (
<div style={{pointerEvents:'none'}}>
<div style={{pointerEvents:'auto'}}>This can be clicked</div>
{props.children}
</div>
)
It is not robust, because if any of the children have pointer-events set to auto, they will be clickable too. See if it fits your needs. Also, it will kill hover and other mouse events.

Use CSS Grid to put a div on top!
A transparent div rendered on top of another div will intercept click events.
CSS Grid can be used (abused?) to make a single grid area (using grid-template-areas) and assign multiple elements to it (using grid-area).
JSX
const ClickGuard = ({allow, block}) => (
<div className='click-guard-area'>
<div className='click-guard-allowed'>{props.allow}</div>
<div className='click-guard-block' />
<div className='click-guard-blocked'>{props.block}</div>
</div>
)
CSS
.click-guard-area {
display: grid;
grid-template-areas: 'click-guard';
height: 100%;
width: 100%;
}
.click-guard-allowed {
grid-area: click-guard;
height: 100%;
width: 100%;
z-index: 2;
}
.click-guard-block {
grid-area: click-guard;
height: 100%;
width: 100%;
z-index: 1;
}
.click-guard-blocked {
grid-area: click-guard;
height: 100%;
width: 100%;
}
Note that ClickGuard expects two props: allow and block. These should be JSX. The React docs explain passing React elements here.
<ClickGuard
allow={<div>I can be clicked!</div>}
block={<div>No clicks for me. 😞</div>}
/>

You cannot change the props within an element thus its children props.
An alternative solution may be possible with React.cloneElement,
Here is a simple peace of code for you:
const Example = props => (
<div>
<div>This can be clicked</div>
{props.children.map((child)=>
React.cloneElement(child, {
disabled: true
})
)}
</div>
)

Related

Is there a way to stack sticky headers in react native?

I'm having a table (two directional scroll) with a sticky header showing the title of columns. If it wouldn't support two directional scroll, I could just place the header outside of the scroll view, but it's not the case.
I want to implement grouping of rows (basically SectionList with stickySectionHeadersEnabled). There an upcoming section header replaces the previous section header, which is the expected behaviour for my case. However, I want to have two sticky headers stay in place (the table header, and the current section header). I couldn't find a way to set the top value for the sticky headers as in html:
.container {
width: 200px;
height: 200px;
position: relative;
overflow: scroll;
}
.tableHeader, .sectionHeader {
position: sticky;
}
.tableHeader {
top: 0;
}
.sectionHeader {
top: 20px;
}
.section {
height: 500px;
width: 500px;
}
.section:last-of-type {
background: wheat;
}
<div class='container'>
<div class='tableHeader'>Table header</div>
<div class='section'>
<div class='sectionHeader'>Section header 1</div>
</div>
<div class='section'>
<div class='sectionHeader'>Section header 2</div>
</div>
</div
Any way to earn the above in react native?
I was thinking about the implementation of nesting two ScrollViews, where the outer could be horizontal, and it could have the first child as the table header, and the second is the SectionList. It could work, but not being able to scroll diagonally is very annoying for me, had a hard time to implement it on ios, and wasn't even able to do it on android, so it would be a last case.
You can use a FlatList with stickyHeaderIndices where the indices are the indices of the headers in your array.
const renderItem = ({ item }) => <Item title={item.title} />;
<FlatList
data={DATA}
stickyHeaderIndices={[0, 6]}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
For the diagonal scroll, it should work on iOS with directionalLockEnabled set to false according to the docs but it doesn't.
For both ScrollViews to work on android the nestedScrollEnabled property should be set to true.
Here's a snack with an implementation, it doesn't seem to work on the web but it works on the iOS and android emulators:
https://snack.expo.dev/yyz6ro3Hi

How can I implement css hover effect in react inline-styling?

I am trying to implement a hover effect in the react component using react inline-styling.
const InfoWindow: React.FC<IInfoWindowProps> = ({ room }) => {
const info_window_image = {
width: "100%",
height: "168px",
background: `url(${room.pictures[0].image.large}) no-repeat`,
backgroundSize: "contain",
cursor: 'pointer'
};
return (
<div className="info_window_container">
<div style={info_window_image} />
</div>
)
};
div tag under info_window_container gets style object info_window_image .
I can successfully receive an image from API but I want to give zoom-in animation when the user hovers the image in the component.
I gave className to the div and styled in CSS file however it does not work. Styles I declared in CSS file do not render.
How can I make hover or focus effect in react-inline-styling?

How to create a login screen with changing background images?

I have a login page. As per the wireframes, there are images in the background and they change in every few seconds.
Consider it like a splash screen with a login form. I have developed the login form. But the splash screen is the issue.
How do I achieve this with react.js?
Any leads would be helpful.
The gist is to setup a background image container (likely taking 100% of the view height and width) with the following CSS:
// keep image from scrolling when content is scrollable
background-attachment: fixed;
// center the image within the container
background-position: center;
// scale the image to cover the container the smaller quantity of width or height
background-size: cover;
width: 100vw;
height: 100vh;
Then in code choose your flavor of CSS-in-JS. I like styled-components, but for brevity I'll use an in-line style attribute:
style={{ backgroundImage: `url(${/* pass reference to image */})` }}
Sample Component:
import bgImgArray from './assets/img';
function App() {
const [index, setIndex] = useState(0);
useEffect(() => {
const timer = setInterval(() => setIndex(i => i + 1), 5000);
return () => clearInterval(timer);
}, []);
const bgImg = bgImgArray[index % bgImgArray.length];
return (
<div
className="App backgroundContainer"
style={{
backgroundImage: `url(${bgImg})`
}}
>
/* container content, children, etc.. */
</div>
);
}

Add Space Between Row Elements in React BootStrap

I am new to React and react-bootstrap. I have a Row component and would like spacing between the top of the screen and also between the individual row elements. I am currently just editing its CSS but heard that it may be bad to mess with the CSS of frameworks?
const Styles = styled.div`
.background {
background: url(${backgroundImage}) no-repeat fixed bottom;
background-size: cover;
height: 100vh;
position: relative;
}
#row {
position: relative;
top: 200px;
}
`;
class Signup extends React.Component {
render() {
return (
<Styles>
<div className="background">
<Container>
<Row id="row" className="justify-content-md-center">
<ExtraInfo />
<SignupForm />
</Row>
</Container>
</div>
</Styles>
);
}
}
export default Signup;
Use Form.Group in React-Bootstrap. It adds 15px padding on columns to separate the content of the columns.
I'm not saying this is the best solution, but I have just created a CSS class that sets a margin attribute to 5px and then applied it to the Row element where I need it. This works for me, but I'm welcome to better answers.
For space at the top and bottom of the screen, what I have done is create a "spacer" component which I import and use to create space between elements.
I know what you mean about messing with the CSS though and this method might be a bit "hacky".
Example JSX:
<>
<p><strong>My Categories</strong></p>
{
catList.map((cat,i) => (
<Row key={i} className="add-space">
<Col><strong>Category {i+1}</strong></Col>
<Col>{cat}</Col>
<Col><Button onClick={() => removeCategory(cat)}>Remove</Button></Col>
</Row>
))
}
</>
Example CSS:
.add-space {
margin: 4px;
}
Example Spacer:
const Spacer = props => {
return (
<div style={{height:props.height}}></div>
);
}
export default Spacer;
Use:
<Spacer height="1rem" />

How do I make component not visible in UI even when it is in the DOM?

I have a function printDocument that onClick downloads the pdf that has the content of <ComponentViewToDownload/>. I do not want to show that component in the UI, just Download button. Is there a way to achieve this?
render() {
return (
<div>
<button onClick={this.printDocument}>Download</button>
<div id="divToPrint" >
<ComponentViewToDownload/>
</div>
</div>
);
}
Found a solution:
style={{
position: "absolute",
top: "-9999px",
left: "-9999px"
}}
Works well and doesn't mess up the main UI layout

Resources