How to pass props to component in same file? - reactjs

I want to pass the value of width to the component Color from component Scala as prop. But I am getting an error width is not defined, or width not found. Can someone help me. This is a tsx file (typescript)
const Scale = (props: any) => {
const brewer = props.brewer;
let Length = props.Length; //accepting value from colorlegend <- flowlines
if (Length == 0) {
let width = 1;
} else {
let width = Math.floor(120 / Length);
console.log(width);
}
const colors = getColors(chroma.scale(brewer), LENGTH);
return (
<div>
<div
style={{
width: 30,
fontSize: '1.5em',
textAlign: 'right',
display: 'flex',
flexDirection: 'column',
}}
>
{brewer}
</div>{' '}
{colors.map(Color)}
</div>
);
};
const Color = (color: any, props: any) => (
<div
style={{
backgroundColor: color,
width: props.width,
height: 15,
display: 'inline-block',
}}
/>
);

Try to change the return value of the map function:
colors.map(color => <Color key={color} color={color} width={<specify-a-width>});
You should also consider the color as a component prop
const Color = (props: any) => (
<div
style={{
backgroundColor: props.color,
width: props.width,
height: 15,
display: 'inline-block',
}}
/>
);

Related

Drop Event won't be fired (react-draggable)

Currently i'm writing draggable component with react-draggable.
However, when i drag my component into another component (outside of component parent), onDrop event won't fire.
Below here is my component:
const DraggableBaseCard = (props: {
id: String,
positionX: Number,
positionY: Number,
positionZ: Number,
width: Number | String,
height: Number | String,
zoomFactor: Number,
isLocked: Boolean,
}) => {
const boardStore = useBoardStore();
const [position, updatePosition] = useState({
x: props.positionX,
y: props.positionY,
});
const onDragStop = (_, elementData) =>
handleDrop(elementData, updatePosition, boardStore, props.id);
return (
<Draggable
defaultClassName="gulabee-base-card"
disabled={props.isLocked}
handle={props.customHandle ?? ".draggable-component"}
bounds={props.bounds ?? { left: 0, top: 0 }}
defaultPosition={position}
onStop={props.onStop ?? onDragStop}
onDrag={props.onDrag}
scale={props.zoomFactor || 1}
key={props.id}
>
<div
{...props}
className={`draggable-component ${props.className || ""} p-2`}
onDragStart={(e) => {
e.dataTransfer.setData("cardID", props.id);
console.log("Drag Start");
}}
style={{
zIndex: props.positionZ,
cursor: "pointer",
position: "absolute",
width: props.width || "10rem",
height: props.height || "auto",
border: props.noBorder
? undefined
: "solid 1px rgba(0, 0, 0, 0.3)",
}}
>
<Dropdown
overlay={() => CardContextMenu(props.id)}
onContextMenu={(e) => {
e.stopPropagation();
}}
trigger={["contextMenu"]}
>
<div
className="card-children"
style={{ width: "100%", height: "100%" }}
>
{props.children}
</div>
</Dropdown>
</div>
</Draggable>
);
};
const handleDrop = (elementData, updatePosition, boardStore, cardId) => {
updatePosition({
x: roundByGridSize(elementData?.x || 0, GRID_SIZE),
y: roundByGridSize(elementData?.y || 0, GRID_SIZE),
});
boardStore.cards[cardId].positionX = elementData?.x / GRID_SIZE;
boardStore.cards[cardId].positionY = elementData?.y / GRID_SIZE;
};
Here is how i test drop area:
const PocketBag = observer((props) => {
return (
<div style={{ height: "100%" }} onDrop={(e) => alert("Dropped")}>
Dropzone
</div>
);
});
When i drag the DraggableBaseCard into PocketBag, the alert won't show up.
The onDragStart event of the DraggableBaseCard is not working either unless i set draggable props to true, but it somehow conflict with Draggable component
Please help me with my problem i'm crying :(
You need to allow dropping by adding this code to the element to want to drop on. HTML by default doesn't allow drops
onDragOver={event=>event.preventDefault()}

Fixed row and column with react-virtual module

When I override the div with a column index of 0 that has position absolute and give it a position sticky with left: 0 the first column style just breaks.
Is it possible to have fixed columns or rows with react-virtual?
combineStyles is a function that I wrote to make me able to conditionally add some styles to an element.
const VirtualTable = <T,>({ columns, data }: ITableProps<T>) => {
const parentRef = React.useRef<HTMLDivElement | null>(null);
const rowVirtualizer = useVirtual({
size: data.length,
parentRef,
estimateSize: React.useCallback((i) => 50 as any, []),
overscan: 5,
});
const columnVirtualizer = useVirtual({
horizontal: true,
size: columns.length,
parentRef,
estimateSize: React.useCallback((i) => 100, []),
overscan: 5,
});
return (
<>
<div
ref={parentRef}
className="List"
style={{
height: `calc(100vh) - ${shapes.headerHight}px`,
width: `100%`,
overflow: "auto",
}}
>
<div
style={{
height: `${rowVirtualizer.totalSize}px`,
width: `${columnVirtualizer.totalSize}px`,
position: "relative",
}}
>
{rowVirtualizer.virtualItems.map((virtualRow) => (
<React.Fragment key={virtualRow.index}>
{columnVirtualizer.virtualItems.map(
(virtualColumn, columnIndex) => {
return (
<div
key={virtualColumn.index}
style={combineStyles([
{
position: "absolute",
top: 0,
left: 0,
width: `${virtualColumn.size}px`,
height: `${virtualRow.size}px`,
transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`,
},
columnIndex === 0 &&
{
position: "sticky",
},
])}
>
Cell {virtualRow.index}, {virtualColumn.index}
</div>
);
}
)}
</React.Fragment>
))}
</div>
</div>
</>
);
};

react setState not rendering everytime button is pressed

I'm trying to use setState to access my css const mystyle object to change the background color on the squares from blue to red but everytime the button is pressed. It seems everytime I press the button the Setstate does not render on screen any advice or help? Would be greatly appreciated
class MyHeader extends React.Component {
constructor(props){
super(props)
this.state = {backgroundColor: 'blue'};
}
render() {
const mystyle = {
borderRadius: "10px",
background: this.state.backgroundColor,
padding: "10px",
width: "100px",
height: "100px",
marginTop: "10px",
lineHeight: "80px",
color: "dimGrey",
fontWeight: "bold",
fontSize: "3em",
textAlign: "center"
};
function State() {
this.setState({backgroundColor: 'red'})
}
return (
<div>
<h1 style={mystyle}></h1>
<h1>{this.state.backgroundColor}</h1>
</div>
);
}
}
function Test() {
function Test2() {
setchange(change + Math.floor(Math.random() * 10));
if(change > 20) {
setchange(change + Math.floor(Math.random() - 10))
}
}
const [change, setchange] = React.useState(1)
return (
<div>
<h1>click the button to randomize colors</h1>
<button onClick={this.State}>Randomize colors!</button>
<div className='.flex-item'></div>
<h1>{change}</h1>
<div className="flex-item"></div>
<MyHeader />
<MyHeader />
</div>
);
}
ReactDOM.render(<Test />, document.getElementById("root"));
my codepen link to the code
The main issue is trying to do something where the child component, MyHeader, has the function to change state, but trying to invoke it from the parent component, Test. It's just simpler to pass the color as a prop from Test to MyHeader.
Alternatively, you can do the useContext thing, but I think this is easier. I've stripped out all superfluous code that wasn't getting used. You can of course, add them back as you need to.
const MyHeader = ({backgroundColor}) => {
const mystyle = {
borderRadius: "10px",
background: backgroundColor,
padding: "10px",
width: "100px",
height: "100px",
marginTop: "10px",
lineHeight: "80px",
color: "dimGrey",
fontWeight: "bold",
fontSize: "3em",
textAlign: "center"
};
return (
<div>
<h1 style={mystyle}></h1>
<h1>{backgroundColor}</h1>
</div>
);
}
}
const Test = (props) => {
const [backgroundColor, setBackgroundColor] = useState("blue");
const onButtonClick = () => {
setBackgroundColor("red");
}
return (
<div>
<h1>click the button to randomize colors</h1>
<button onClick={onButtonClick}>Randomize colors!</button>
<div className='.flex-item'></div>
<h1>{change}</h1>
<div className="flex-item"></div>
<MyHeader backgroundColor={backgroundColor} />
</div>
);
};

Material UI Custom Hover Color

Haven't made this feature before where you can change the color of button's hover.
I have already made a feature to change the radius with a slider, background color and font color using color-picker. However, I noticed the hover (for background AND font) could be better.
Here is the code:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Grid from "#material-ui/core/Grid";
import Slider from "#material-ui/core/Slider";
import Input from "#material-ui/core/Input";
import Button from "#material-ui/core/Button";
import { ChromePicker } from "react-color";
const useStyles = makeStyles((theme) => ({
root: {
"& > *": {
margin: theme.spacing(1)
}
},
Button: {
width: 150,
height: 50,
borderRadius: "var(--borderRadius)"
},
color: {
width: "36px",
height: "14px",
borderRadius: "2px"
},
swatch: {
padding: "5px",
background: "#fff",
borderRadius: "1px",
display: "inline-block",
cursor: "pointer"
},
popover: {
position: "absolute",
zIndex: "2"
},
cover: {
position: "fixed",
top: "0px",
right: "0px",
bottom: "0px",
left: "0px"
}
}));
export default function InputSlider() {
const classes = useStyles();
const [value, setValue] = React.useState(30);
const [color, setColor] = React.useState({ r: 0, g: 0, b: 0, a: 1 });
const [fontColor, setFontColor] = React.useState({
r: 255,
g: 255,
b: 255,
a: 1
});
const [displayColorPicker, setDisplayColorPicker] = React.useState(true);
const handleSliderChange = (event, newValue) => {
setValue(newValue);
};
const handleInputChange = (event) => {
setValue(event.target.value === "" ? "" : Number(event.target.value));
};
const handleBlur = () => {
if (value < 0) {
setValue(0);
} else if (value > 30) {
setValue(30);
}
};
const handleClick = () => {
setDisplayColorPicker(!displayColorPicker);
};
const handleClose = () => {
setDisplayColorPicker(false);
};
const handleChange = (color) => {
setColor(color.rgb);
};
const handleFontColorChange = (color) => {
setFontColor(color.rgb);
};
return (
<div className={classes.root}>
<style>
{`:root {
--borderRadius = ${value}px;
}`}
</style>
<Button
style={{
borderRadius: value,
background: `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`,
color: `rgba(${fontColor.r}, ${fontColor.g}, ${fontColor.b}, ${fontColor.a})`
}}
variant="contained"
color="primary"
value="value"
onChange={handleSliderChange}
className={classes.Button}
>
Fire laser
</Button>
<Grid container spacing={2}>
<Grid item xs>
<Slider
value={typeof value === "number" ? value : 0}
onChange={handleSliderChange}
aria-labelledby="input-slider"
/>
</Grid>
<Grid item>
<Input
value={value}
margin="dense"
onChange={handleInputChange}
onBlur={handleBlur}
inputProps={{
step: 10,
min: 0,
max: 24,
type: "number"
}}
/>
</Grid>
</Grid>
<div>
<div style={useStyles.swatch} onClick={handleClick}>
{displayColorPicker} <p class="h4">Background</p>
<div style={useStyles.color} />
</div>
{displayColorPicker ? (
<div style={useStyles.popover}>
<div style={useStyles.cover} onClick={handleClose}></div>
<ChromePicker color={color} onChange={handleChange} />
</div>
) : null}
</div>
<div>
<div style={useStyles.swatch} onClick={handleClick}>
{displayColorPicker} <p class="h4">Font</p>
<div style={useStyles.color} />
</div>
{displayColorPicker ? (
<div style={useStyles.popover}>
<div style={useStyles.cover} onClick={handleClose}></div>
<ChromePicker color={fontColor} onChange={handleFontColorChange} />
</div>
) : null}
</div>
</div>
);
}
And here is the sandbox - https://codesandbox.io/s/material-demo-forked-t8xut?file=/demo.js
Any advice?
Does anyone have a good Material UI article for editing/cool features and projects to play with?
You need to pass props to makeStyles.
First, pass fontColor variable as below when declaring classes:
const classes = useStyles({ hoverBackgroundColor, hoverFontColor })();
then in the useStyles, you can have access to the fontColor as a prop, as below:
const useStyles = ({ hoverBackgroundColor, hoverFontColor }) =>
makeStyles((theme) => ({
Button: {
width: 150,
height: 50,
borderRadius: "var(--borderRadius)",
"&:hover": {
backgroundColor: `rgba(${hoverBackgroundColor.r}, ${hoverBackgroundColor.g}, ${hoverBackgroundColor.b}, ${hoverBackgroundColor.a}) !important`,
color: `rgba(${hoverFontColor.r}, ${hoverFontColor.g}, ${hoverFontColor.b}, ${hoverFontColor.a}) !important`
}
},
sandbox

React-Rnd one block inside other

I am using the react-rnd library to drag and resize blocks. I created a page. It creates a gray container on it and I click on the "add global container" button and a container appears on the field that I can move and resize within the parent gray container
in the left corner of the created container there is a purple button, clicking on it, another container will be created inside this container and now the first container will be the parent for the new one created.
the problem is that I can resize the inner container, but I can not move it, or rather, it moves with the parent component. the inner component will move inside the outer only when the parent component touches the borders of its parent, the gray container
in code it looks like this
I have a component , which in itself contains a component
the Box component is called inside Rdn - this is the block that you see on the screen, Rdn makes it move
type Props = {
width: string;
height: string;
color: string;
};
class BoxWrapper extends React.Component<Props> {
state = {
width: "100",
height: "40",
x: 0,
y: 0,
};
render() {
const { width, height, color } = this.props;
return (
<Rnd
size={{ width: this.state.width, height: this.state.height }}
position={{ x: this.state.x, y: this.state.y }}
bounds="parent"
onDragStop={(e: any, d: any) => {
e.stopPropagation();
this.setState({ x: d.x, y: d.y });
}}
minHeight={16}
minWidth={16}
onResize={(
e: any,
direction: any,
ref: any,
delta: any,
position: any
) => {
this.setState({
width: ref.style.width,
height: ref.style.height,
...position,
});
}}
>
<Box
x={this.state.x}
y={this.state.y}
width={this.state.width}
height={this.state.height}
externalHeight={height}
externalWidth={width}
color={color}
/>
</Rnd>
);
}
}
export default BoxWrapper;
inside the Box component, the purple button is checked and if it is pressed, you need to create the BoxWrapper component
type BoxProps = {
x: number;
y: number;
width: string;
height: string;
externalWidth: string;
externalHeight: string;
color: string;
};
class Box extends React.Component<BoxProps> {
state = {
isClick: false,
isCreate: false,
};
render() {
const {
x,
y,
width,
height,
externalWidth,
externalHeight,
color,
} = this.props;
const externalH = parseInt(externalHeight);
const externalW = parseInt(externalWidth);
const boxWidth = parseInt(width);
const boxHeight = parseInt(height);
const xUpperLeft = x;
const yUpperLeft = y;
const xUpperRight = x + boxWidth;
const yUpperRight = y;
const xDownLeft = x;
const yDownLeft = y + boxHeight;
const xDownRight = x + boxWidth;
const yDownRight = y + boxHeight;
return (
<>
<div
style={{
margin: 0,
height: "100%",
padding: 0,
backgroundColor: color,
}}
>
<div className="wrapper">
<button
style={{
width: 0,
height: "14px",
borderRadius: "1px",
backgroundColor: "#fff",
display: "flex",
justifyContent: "center",
fontSize: 9,
}}
onClick={() => this.setState({ isClick: !this.state.isClick })}
>
?
</button>
<button
style={{
width: 0,
height: "14px",
borderRadius: "1px",
backgroundColor: "#a079ed",
display: "flex",
justifyContent: "center",
fontSize: 9,
}}
onClick={() => this.setState({ isCreate: !this.state.isCreate })}
/>
</div>
{this.state.isCreate && (
<BoxWrapper
width={width}
height={height}
color="#42d5bc"
/>
)}
</div>
{this.state.isClick && (
<Tooltip
leftDistance={xUpperLeft}
topDistance={yUpperLeft}
rightDistance={externalW - xUpperRight}
bottomDistanse={externalH - yDownLeft}
/>
)}
</>
);
}
}
how can I make it so that I can freely move the inner container without automatically dragging the parent container
I tried in the onDragStop method in Rnd to specify event.stopPropafgation(), but it doesn’t work at all, I don’t know what to do
this is a working example of my problem the inner Rnd container has the bounds of the bounds = "parent" and the outer one is "window"
problem resolved
you need to replace the onDragStop method with onDrag and specify
event.stopImmediatePropagation();
working example with corrections of the previous

Resources