I created a custom crosshair using react and I can't seem to get it click on certain elements such as a button it won't let me click the button but If I removed the custom crosshair the button onclick will let me click and it will run the function associated with the button I tried creating a zIndex css to have the cursor overlapped the other crosshair but that did not work any suggestion to make it where I can click other elements and the function can run? written via codepen
const { useRef } = React
const Main = props => {
const cursor = {
cursor: "crosshair",
width: "20PX",
height: "20PX",
position: "fixed",
};
const borders = {
width: "800px",
height: "500px",
backgroud: "#ccc",
border: "4px solid #333"
}
const textInput = useRef()
React.useEffect(() => {
document.addEventListener("mousemove", (event) =>{
textInput.current.style.top = event.clientY + 'px'
textInput.current.style.bottom = event.clientX + 'px'
textInput.current.style.left = event.clientX + 'px'
textInput.current.style.right = event.clientY + 'px'
})
console.log("dsadas")
});
return (<div style={borders} >
<div ref={textInput} style={cursor}>
</div> <button >dsa2222ads</button></div>)
}
ReactDOM.render(<Main />, document.getElementById("root"));
The code in the question, while ingenious, cannot be fixed as-is, because of 2 main reasons:
The cursor element is receiving all click events instead of what's beneath it;
As pointed out in comments, my initial suggestion (to use pointer-events: none; styling on the cursor element) does make the button work properly, but the cursor: crosshair; style stops working because the element gets ignored when it comes to ALL pointer aspects, not only events.
The following alternative relies purely on CSS, more specifically on the * selector to assign the cursor: crosshair; style to all elements at any depth inside the containing element (and also place it on the borders element). The markup gets lighter since we don't need the cursor element any more and no more code to move it around the page. Also no more document-level event listeners.
.borders {
cursor: crosshair;
width: 800px;
height: 500px;
background: #ccc;
border: 4px solid #333;
}
.borders * {
cursor: crosshair;
}
<div class="borders">
<button onClick="alert('Ok!')">Button</button>
</div>
Now, should you need a different cursor on just some internal elements, you can easily achieve that using selector specificity to target that element and put cursor: auto; or whatever you need on it. If you want to restore the crosshair on that element's children, just re-apply the * selector, and so on. So you have complete and granular control over the cursor all with CSS. If a code sample for this scenario is needed, let me know in the comments. Thank you!
Related
I want to see animation when I change width of my sidebar. Material UI is used here (AppBar). I think it's because React just re-renders component quickly. How you would do it? I think it would work if i just changed class or added class.
Also it' necessary to understand that content of StyledAppBar will depend on whether it's opened. So I will need re-render so that the content change
Additional question - do you know how to make AppBar render as tag instead oh tag? :)
const Header = () => {
const [open, setOpen] = useState(true);
const StyledAppBar = styled(AppBar)`
background-color: red;
height: 100vh;
width: ${open ? '240px' : '50px'};
transition: width 1s ease-in-out;
position: fixed;
left: 0;
`;
return (
<StyledAppBar>
<Toolbar>
<Typography>MUI SHOP</Typography>
<ShoppingBasket onClick={() => setOpen(prev => !prev)}/>
</Toolbar>
</StyledAppBar>
);
};
I'm new to Mui and trying to apply animation to components.
What I want to do is, I have four same component and each has its own image.
<MyComponent>some images...</MyComponent>
<MyComponent>some images...</MyComponent>
<MyComponent>some images...</MyComponent>
<MyComponent>some images...</MyComponent>
const MyComponent = styled("div")((theme) => ({
//... some styles.
// scale up when hovered
'&:hover': {
transform: "scale(1.2)",
marginRight: "20px",
}
}));
If I hover a <MyComponent>, I want to scale up hovered one, and scale down others.
Is there any ways to defined such action by using styled???
I would set a state then use a conditional to change styles .. IE
const [hoverState, setHoverState] = useState(false);
<MyComponent
onMouseOver={setHoverState(true)}
onMouseOut={setHoverState(false)}
style={hoverState ? {transform: "scale(1.2)",marginRight: "20px",} : ''}
>
some images...
</MyComponent>
You can do this with css and styled-components.
Note that the styled function is not meant to be called directly, but passed a template literal. Inside the template literal, you can write regular css expressions.
codesandbox
const MyComponent = styled.div`
transform: scale(1);
margin-right: 0px;
:hover {
transform: scale(1.2);
margin-right: 20px;
}
`;
I am using react, styled-components.
When state(visible) is set to true, DropMenu box1 and box2 will be displayed.
We want the ArrowDown icon to flip upward when state is true, and downward when false.
I also want to apply an animation when flipping it.
I want to add an animation like the Dropdown in the following site.
Reference site
code
import "./styles.css";
import styled from "styled-components";
import React, { useState, useCallback } from "react";
import { ArrowDown } from "./ArrowDown";
const Item = styled.div<{ active?: boolean }>`
height: 40px;
width: 300px;
padding: 0px 30px;
&:hover {
background: #fafbfb;
}
`;
const DropMenu = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
color: #899098;
width: 100%;
height: 100%;
font-size: 14px;
font-weight: bold;
gap: 12px;
:hover {
color: gray;
}
div {
display: flex;
align-items: center;
gap: 12px;
}
`;
const DropText = styled.div`
padding-left: 32px;
`;
export const App = () => {
const [visible, setVisible] = useState(false);
const handleDropVisibleChange = useCallback(() => {
setVisible((prevVisible) => !prevVisible);
}, [visible]);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Item onClick={handleDropVisibleChange}>
<DropMenu>
<div>
<span>Menu</span>
</div>
<ArrowDown />
</DropMenu>
</Item>
{visible && (
<div style={{ transition: "all 0.5s ease" }}>
<Item>
<DropMenu>
<DropText>box1</DropText>
</DropMenu>
</Item>
<Item>
<DropMenu>
<DropText>box2</DropText>
</DropMenu>
</Item>
</div>
)}
</div>
);
};
export default App;
TLDR
Change your MenuItem component warpper to something like
const DropMenuWrapper = styled.div<{ visible: boolean }>`
transition: all 0.5s ease;
opacity: ${(props) => (props.visible ? 1 : 0)};
`;
replace the visibility switch mechanism with following
- {visible && (
- <div style={{ transition: "all 0.5s ease" }}>
+ <DropMenuWrapper visible={visible}>
similar action can be added to the arrow-down icon also with style
(The ArrowDown SVG icon must accept style if it is custom written component)
<ArrowDown
style={{
transition: "all 0.5s ease",
transform: `rotate(${visible ? 0 : "0.5turn"})`
}}
/>
Why this happened:
When a component (sub-component/element) is mounted in react, it starts a complete life cycle toward browser paint.
So it is must have the property which causes the element to animate, for example, I added the opacity transition to the example itself, forcing it to animate in the first look and in disappearing.
Although it comes with some performance cost of having unseen elements still in the dom (but not visible), making it bad for accessibility too, it is the simplest way to achieve this behavior.
Consider this example If you have an animated element, does it show the animation if you refresh the browser if the answer is yes, it will show animation in react too.
Another way of doing some animation in react.
Using third-party library react-transtion-group which is heavily used in lots of packages e.g. Material-UI.
In this case you can also trigger the end event and start to unmount the component as the animation disappears and end completely.
Using framer motion
If you want to take your understanding of what is needed for the transition when the component is unmounted and removed from aka dom, I highly encourage you to read the animation section of svelte docuementation
What I did, what might look stupid to more advanced developers was implement a simple check that would switch icons.
Note: This doesn't have an animation, though. It's just a simple switcharoo
define state in component
const [isOpen, setIsOpen] = useState(false);
Check whether icon is open or closed, if open, ExpandLessIcon, if closed ExpandMoreIcon.
<ExpandLessIcon
onClick={() => {
setIsOpen(!isOpen);
}}
/>
) : (
<ExpandMoreIcon
onClick={() => {
setIsOpen(!isOpen);
}}
/>
)}
The way it works is, once clicked, it'll just flip the true false state over and over, which in turn will change icons.
I am trying to create an custom Radio button like feature. By putting onClick on div to change the state value and I am not able to change the same. Please help me understand what I am missing on.
const [category, setCategory] = useState("");
const handleSubmit = e => {
console.log(e);
setCategory(e.target.value);
};
return (
<>
<CenterAlignedColumnContainer>
<FormHeadingText>
<FormSectionHeadingTextContainer>
Category
</FormSectionHeadingTextContainer>
</FormHeadingText>
<CategoryContainer>
<TextRadioButton
value="Salads"
onClick={handleSubmit}
name="category"
>
<RadioButtonText>
<TextContainer>Salads</TextContainer>
</RadioButtonText>
</TextRadioButton>
<TextRadioButton value="Pasta" onClick={handleSubmit} name="category">
<RadioButtonText>
<TextContainer>Pasta</TextContainer>
</RadioButtonText>
</TextRadioButton>
</CategoryContainer>
<PartialWidthDivider />
</CenterAlignedColumnContainer>
</>
);
}
Styled div for custom Radio button
export const TextRadioButton = styled.div`
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 10px;
background: rgba(176, 167, 230, 0.5);
box-shadow: 0px 4px 4px rgba(176, 167, 230, 0.5);
border-radius: 20px;
margin-left: -10px;
margin: 8px;
`;
div does not have a value property, so you should reference it i.e. as a passed prop:
<TextRadioButton value='something' onClick={handleSubmit(props.value)} />
and use it explicitly
handleSubmit(value) {
setCategory(value);
}
change your onClick method to :
onClick={(e)=>handleSubmit(e}
or
onClick={
(e)=>{
console.log(e);
setCategory(e.target.value);
};
So there's a couple of problems wrong with this, this first and foremost being that you have a pseudo-element covering your entire display:
export const Background = styled.div`
width: 100%;
&:before {
display: block;
position: absolute;
width: 100%;
height: 400vh;
content: "";
background: url(https://res.cloudinary.com/antilibrary/image/upload/v1595154947/Piatto/backgroundFormNew_sk7yie.svg)
repeat center center;
opacity: 0.5;
}
`;
When an element is :before it means it is above any further elements in the stacking context, the same way that hard-coded elements are. A simple solution is to give the pseudo-element z-index: -1, which will ensure that it is placed behind everything else. Ideally, however, you would not use a pseudo-element at all, but instead a distinct div placed absolutely behind everything.
The second is that your buttons are not using good semantic HTML, and as a result you will not be able to target value, which does not exist on divs. Additionally, since the text of the button is separate from the button itself, there will be cases where it returns undefined anyway as the target of the event does not hold the button's value.
What I suggest you do first is change TextRadioButton to be a styled.button, you may need to adjust some of your styles to accommodate this. Then, change the event handler to the following:
const handleSubmit = e => {
const value = e.currentTarget.value;
setCategory(value);
};
The currentTarget of an event is the element where the event is registered, not whichever child element actually triggered it, which you access with regular target. This way, no matter which part of the button is clicked on, it will always reference the value on the top level of the button component.
I've read the docs many times over and still don't fully understand how to style the React slider via inline CSS (https://github.com/react-component/slider).
I see that you need to pass a handle props to the slider with the css and some kind of component with offset and value props. When I try to do this, my CSS comes back horrible with the knobs not moving and the slider being all over the place. Regular styling doesn't work on the slider.
This is how my component that I pass on to the slider component looks like:
import React from "react";
export default class SliderStyle extends React.Component {
render(){
let style = {
position: "absolute",
left: "0",
height: "15px",
borderRadius: "8px",
backgroundColor: "#000"
};
let tracker = {
position: "absolute",
marginLeft: "-7px",
marginTop: "-5px",
width: "14px",
height: "14px",
cursor: "pointer",
borderRadius: "50%",
border: "solid 2px #000",
backgroundColor: "#fff"
}
return(
<div style={style}><div style={tracker}></div></div>
)
}
}
Then in the main component:
<Slider range allowCross={false} handle={<SliderStyle/>} value={this.state.range} onChange={this.onSliderChange.bind(this)}/>
I'm assuming the div I return from the component that I pass into the Slider component is the actual slider, and the div inside the first one is what will be the knob. The colors change, but the slider knob doesn't move when values change.
Is there something I'm not getting here?
Looking at the example given by slider about creating a custom handle - http://react-component.github.io/slider/?path=/story/rc-slider--slider - first I'd like to explain the handle object. This will only be replacing the handle in your slider.. what I think you refer to as the "knob". This does not change the styling of the entire slider (you should use Slider's className prop to change the non-handle slider styles).
Also, you need to learn about the offset and value props passed to your handle component. The offset prop is needed to determine the percent left your handle needs to be. Without using this, your handle will not move, which seems to be what you are currently experiencing. The value prop should be displayed to show users what value the slider is currently at (i.e. 3 out of 10). For example:
const handle = {
position: "absolute",
transform: 'translate(-50%, -50%)',
width: "14px",
height: "14px",
cursor: "pointer",
borderRadius: "50%",
border: "solid 2px #000",
backgroundColor: "#fff"
};
const valueBubble = {
position: "absolute",
top: "-10px",
fontSize: "14px"
};
export default class Handle extends React.Component {
render(){
const handleStyle = Object.assign({ left: `${this.props.offset}%` }, handle);
return(
<div style={handleStyle}>
<div style={valueBubble}>{this.props.value}</div>
</div>
)
}
}
I have not run this code, but this should produce something like a circular handle with a bubble above it holder the slider's current value.