making the position of a popconfirm static - reactjs

I am using a popconfirm to show up when trying to close a modal, I want the popconfirm position to be below the X button of the modal, I have tried to move its position with the "overlaystyle" property and if I edit the values while the popconfirm is open it works, but if the screen dimensions change or the popconfirm is closed.
it returns to its original position, is there any way to make it stay below the X of the modal?
import { ExclamationCircleFilled } from "#ant-design/icons";
import { Popconfirm } from "antd";
import { useEffect, useState } from "react";
type EditModalCloseType = {
width: number
popupOpen: boolean;
onConfirm: () => void;
onCancel: () => void;
};
export const EditModalClose = ({width, popupOpen, onConfirm, onCancel }: EditModalCloseType) => {
useEffect(() => {
calculateOverlayStyle(width);
}, [width]);
const description = "¿Estás seguro de salir sin actualizar? los cambios se perderan"
const calculateOverlayStyle = (width: number) => {
setOverlayStyle({
...(width < 688 && { marginLeft: '20px', marginTop: '-160px' }),
...(width < 1300 && { position: 'absolute', top: '50%', left: '50%' }),
...(width >= 1300 && { position: 'absolute', top: '50%', left: '50%' })
});
}
const [overlayStyle, setOverlayStyle] = useState({});
return <Popconfirm
title={description}
open={popupOpen}
placement="bottom"
autoAdjustOverflow={true}
overlayStyle={overlayStyle}
icon={<ExclamationCircleFilled style={{ color: 'red' }} />}
okText="Salir"
okButtonProps={{ style: { backgroundColor: 'red', color: 'white' } }}
onConfirm={onConfirm}
cancelText="Regresar"
onCancel={onCancel}
/>
}
const PopupCancel = () => {
setPopupOpen(false);
};
const PopupConfirm = () => {
resetFields();
setPopupOpen(false);
setOpenModal(false);
}
I tried to create a function according to the width of the screen that would adjust it according to that property but the same error I mentioned in the post keeps occurring.

Related

re-position react-rnd elements with a css transition

I have a list of two elements scenes rendered as <Rnd /> components from "react-rnd". What I'd like to happen is when I drag one element close to another one they should swap positions, in the list and in the UI. so [first, second] becomes [second, first]. The <Rnd /> position is controlled, this is the code I'm using:
import { useState } from "react";
import "./styles.css";
import { Rnd, Position, DraggableData } from "react-rnd";
interface IScene {
id: string;
name: string;
position: Position;
}
function Scene({
scene,
activeScene,
setActiveScene,
onDrag
}: {
scene: IScene;
activeScene: string;
setActiveScene: (id: string) => void;
onDrag: (d: DraggableData) => void;
}) {
const [dragged, setDragged] = useState(false);
return (
<Rnd
default={{
x: 0,
y: 0,
width: "200px",
height: "100px"
}}
position={scene.position}
onDragStart={() => setDragged(true)}
onDragStop={() => setDragged(false)}
onDrag={(_, d) => onDrag(d)}
onMouseDown={() => setActiveScene(scene.id)}
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "gray",
transition: dragged ? "" : "transform 0.5s",
border: "1px solid",
borderColor: activeScene === scene.id ? "white" : "gray",
zIndex: activeScene === scene.id ? "1" : "0"
}}
>
{scene.name}
</Rnd>
);
}
const initialScenesState = [
{
id: "1",
name: "first",
position: {
x: 0,
y: 0
}
},
{
id: "2",
name: "second",
position: {
x: 200,
y: 0
}
}
];
export default function App() {
const [scenes, setScenes] = useState<IScene[]>(initialScenesState);
const [activeScene, setActiveScene] = useState<string>("");
const handleStackScenes = () => {
setScenes((scenes) => {
let currentPosition = 0;
return scenes.map((scene) => {
const result = {
...scene,
position: {
x: currentPosition,
y: 0
}
};
currentPosition += 200;
return result;
});
});
};
const swapScenes = (first: IScene, second: IScene) => {
setScenes((scenes) => {
return scenes.map((scene) => {
if (scene.id === first.id) {
return second;
} else if (scene.id === second.id) {
return first;
} else return scene;
});
});
handleStackScenes();
};
const handleDrag = (scene: IScene) => (d: DraggableData) => {
console.log(d.x);
for (let i = 0; i < scenes.length; i++) {
if (
Math.abs(scenes[i].position.x - d.x) < 30 &&
scenes[i].id !== scene.id
) {
swapScenes(scene, scenes[i]);
}
}
};
console.log(scenes);
return (
<div className="App">
{scenes.map((scene) => (
<Scene
key={scene.id}
scene={scene}
activeScene={activeScene}
setActiveScene={setActiveScene}
onDrag={handleDrag(scene)}
/>
))}
</div>
);
}
The problem that I'm facing with my code, is that when I drag the left element to the right one, the swap happens exactly how I wanted, in the other way around the swap happens but I don't see a transition effect, when I checked what happens on the console, it seems that on the second case, the dom elements don't swap, but just the content and it the first case the actual dom elements move. What am I doing wrong?
EDIT: CodeSandBox

How to display the line number in a mui textfield component

I have to do a little code editor online so I need to display in front of each line the number of the line.
Is it possible with the mui textfield's component ?
I've tried with a which is changing with the number of line of the text fields but they are not aligned and they don't fit
For now my code look like this :
import { Box, TextField } from "#mui/material";
import { MainBox, TextArea } from "./styles";
function useLineText(nbLines = 1): [any, any] {
const [newLine, setNewLine] = useState('1\n')
const updateNewLine = function() {
let myLine = '1\n'
for(let count = 1; count < nbLines; count++) {
myLine = myLine + `${count + 1}\n`
//console.log(myLine)
}
setNewLine(myLine)
}
return [newLine, updateNewLine]
}
const CodeInputField = () => {
const [nbLines, setNbLines] = useState(1)
const [CountLineText, setCountLineText] = useLineText(nbLines)
function replaceWithBr() {
return CountLineText.replace(/\n/g, "<br />")
}
function useHandleTyping(event: React.ChangeEvent<HTMLInputElement>) {
//console.log(event.target.value.toString().split(/\r\n|\r|\n/).length)
setNbLines(event.target.value.toString().split(/\r\n|\r|\n/).length)
setCountLineText(nbLines)
//console.log(CountLineText)
}
return(
<Box sx={MainBox}>
<p dangerouslySetInnerHTML={{__html: replaceWithBr()}}/>
<TextField sx={TextArea} multiline rows={8} onChange={useHandleTyping} id="outlined-multiline-static" />
</Box>
)
}
export default CodeInputField
and for the style :
export const MainBox = () => ({
display: 'flex',
flexDirection: 'row',
border: 1,
borderRadius: 2,
width: 'fit-content',
maxHeight: 1/2,
fontSize: 17.5
})
export const TextArea = () => ({
borderLeft: 1,
'& .MuiOutlinedInput-notchedOutline': {
border: 'none',
borderRadius: 0
}
})
thank for the help

How can I send a canvas with a filter through openvidu?

In progress of a project using WebRTC
I found the code to apply the filter using face_mesh.
The code is as follows
import { FaceMesh } from "#mediapipe/face_mesh";
import React, { useRef, useEffect, createRef } from "react";
import * as Facemesh from "#mediapipe/face_mesh";
import * as cam from "#mediapipe/camera_utils";
import Webcam from "react-webcam";
import "../stream/StreamComponent.css";
function Filter() {
const webcamRef = useRef(null);
const canvasRef = useRef(null);
const connect = window.drawConnectors;
var camera = null;
function onResults(results) {
// const video = webcamRef.current.video;
const videoWidth = webcamRef.current.video.videoWidth;
const videoHeight = webcamRef.current.video.videoHeight;
const videoRef = createRef();
console.log(videoRef);
console.log(connect);
// Set canvas width
canvasRef.current.width = videoWidth;
canvasRef.current.height = videoHeight;
const canvasElement = canvasRef.current;
const canvasCtx = canvasElement.getContext("2d");
canvasCtx.save();
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
canvasCtx.drawImage(
results.image,
0,
0,
canvasElement.width,
canvasElement.height
);
if (results.multiFaceLandmarks) {
for (const landmarks of results.multiFaceLandmarks) {
connect(canvasCtx, landmarks, Facemesh.FACEMESH_TESSELATION, {
color: "#C0C0C070",
lineWidth: 1,
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_RIGHT_EYE, {
color: "#FF3030",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_RIGHT_EYEBROW, {
color: "#FF3030",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_LEFT_EYE, {
color: "#30FF30",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_LEFT_EYEBROW, {
color: "#30FF30",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_FACE_OVAL, {
color: "#E0E0E0",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_LIPS, {
color: "#E0E0E0",
});
}
}
canvasCtx.restore();
}
// }
// setInterval(())
useEffect(() => {
const faceMesh = new FaceMesh({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/#mediapipe/face_mesh/${file}`;
},
});
faceMesh.setOptions({
maxNumFaces: 1,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5,
});
faceMesh.onResults(onResults);
if (
typeof webcamRef.current !== "undefined" &&
webcamRef.current !== null
) {
camera = new cam.Camera(webcamRef.current.video, {
onFrame: async () => {
await faceMesh.send({ image: webcamRef.current.video });
},
width: 640,
height: 480,
});
camera.start();
}
}, []);
return (
<center>
<div className="Filter">
<Webcam
ref={webcamRef}
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zindex: 9,
width: 640,
height: 480,
}}
/>{" "}
<canvas
ref={canvasRef}
className="output_canvas"
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zindex: 9,
width: 640,
height: 480,
}}
></canvas>
</div>
</center>
);
}
export default Filter;
So I'm trying to send a screen with a filter through openvidu
The openvidu code that exports the default camera screen is as follows
import React, { Component } from "react";
import "./StreamComponent.css";
export default class OvVideoComponent extends Component {
constructor(props) {
super(props);
this.videoRef = React.createRef();
}
componentDidMount() {
if (this.props && this.props.user.streamManager && !!this.videoRef) {
console.log("PROPS: ", this.props);
this.props.user.getStreamManager().addVideoElement(this.videoRef.current);
}
}
componentDidUpdate(props) {
if (props && !!this.videoRef) {
this.props.user.getStreamManager().addVideoElement(this.videoRef.current);
}
}
render() {
return (
<video
autoPlay={true}
id={"video-" + this.props.user.getStreamManager().stream.streamId}
ref={this.videoRef}
muted={this.props.mutedSound}
/>
);
}
}
I think apply a canvas object or a canvas.captureStream() to an element**.props.user.getStreamManager().addVideoElement()**
But I don't know how to apply it
It's my first time using openvidu, so I'm facing a lot of difficulties
I'm so sorry if you don't have enough explanation

React DnD how I cannot allow the draggable cannot overlap

Hi Guys I need a guide on this.
I am creating a React DnD. I am creating a Container and I am creating Boxes inside .
How I cannot Drag one over other.
What has more sense, is ask for the position in the callBack and don't allow the drop of the coordinates or modified the ref and "remove the dropable area"?
Anybody with experience in ReactDnD could give me a guide.
import update from 'immutability-helper'
import { useCallback, useState } from 'react'
import { useDrop } from 'react-dnd'
import { Box } from './Box.js'
import { ItemTypes } from './ItemTypes.js'
// This is the size of the area of Drop
const styles = {
width: 500,
height: 500,
border: '1px solid black',
position: 'relative',
}
export const Container = () => {
const [boxes, setBoxes] = useState({
'01': { top: 0, left: 0, title: 'Ship01',width:2,height:1 },
'02': { top: 100, left: 0, title: 'Ship02',width:3,height:1 },
'03': { top: 200, left: 0, title: 'Ship03',width:4,height:1 },
'04': { top: 300, left: 0, title: 'Ship04',width:5,height:1 },
'05': { top: 400, left: 0, title: 'Ship05',width:6,height:1 },
})
const moveBox = useCallback(
(id, left, top) => {
setBoxes(
update(boxes, {
[id]: {
$merge: { left, top },
},
}),
)
},
[boxes, setBoxes],
)
const [, drop] = useDrop(() => ({accept: ItemTypes.BOX, drop(item, monitor) {
const delta = monitor.getDifferenceFromInitialOffset()
const left = Math.round(item.left + delta.x)
const top = Math.round(item.top + delta.y)
moveBox(item.id, left, top)
return undefined}}),[moveBox],)
return (
<div ref={drop} style={styles}>
{Object.keys(boxes).map((key) => {
const { left, top, title,width, height} = boxes[key]
return (
<Box key={key} id={key} left={left} top={top} width={width} height={height} boxes={boxes}> {title} </Box>
)
})}
</div>
)
}

Create simple custom progression bar in React

I'm trying to create my simple progression bar in React using CSS and setInterval. It's not working properly after 10%. Does anyone know why it is happening? Thanks
import React, {useState, useEffect} from 'react';
const Loading = () => {
const [percentage, setPercentage] = useState(0);
const containerStyles = {
height: 20,
width: '100%',
backgroundColor: "#e0e0de",
borderRadius: 50,
margin: 50
}
const fillerStyles = {
height: '100%',
width: `${percentage.toString()}%`,
backgroundColor: 'red',
borderRadius: 'inherit',
textAlign: 'right'
}
const labelStyles = {
padding: 5,
color: 'white',
fontWeight: 'bold'
}
useEffect(() => {
const newPercentage = parseInt(percentage) + 1;
setInterval(() => setPercentage(newPercentage), 1000);
}, [percentage])
return (
<div style={containerStyles}>
<div style={fillerStyles}>
<span style={labelStyles}>{percentage}%</span>
</div>
</div>
)
}
export default Loading;
You should store your interval in a constant and use the cleanup function to clear the last interval each time.
I'd also change how you handle setPercentage and use timeout instead of interval
Something like this:
useEffect(() => {
const timeoutID = setTimeout(() =>
setPercentage(prevPercentage => prevPercentage + 1)
, 1000);
return () => clearTimeout(timeoutID);
}, [setPercentage]);

Resources