How to display the line number in a mui textfield component - reactjs

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

Related

making the position of a popconfirm static

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.

react testing library - text is being found in element but not as expected

I'm writing a tic-tac-toe game with the following two components:
GameBoard handles the graphic representation:
import "./styles.css";
import { clsx } from 'clsx';
import { useEffect, useState } from 'react';
interface Props {
moves?: [number,number][];
handleMove: () => void;
};
type Mark = '' | 'X' | 'O';
const Row = ({row, rIndex, handleMove}) => {
return row?.map((col,cIndex) => <div key={col.toString() + cIndex} onClick={()=>handleMove(rIndex,cIndex)} data-testid="square" style={{border: "1px solid grey", borderRadius: "10px", display: "flex", alignItems: "center", justifyContent: "center", height: '200px', fontSize: "50px"}}>{col}</div>);
};
const GameBoard = ({
moves = [],
handleMove
}:Props) => {
const [sideLength, setSideLength] = useState(3); // sidelength is set in gameboard because the logic for determining if a player has won is independent of it
const cols = Array(sideLength).fill('');
const rows = cols.map(col => Array(sideLength).fill(col.slice()));
for(let i = 0; i < moves.length; i++){
const [y,x] = moves[i];
const mark:Mark = i % 2 === 0 ? 'X' : 'O';
rows[y][x] = mark;
}
return (
<div className="game-board" style={{display:"grid", gridGap: "1%", gridTemplateRows: `repeat(${sideLength}, 1fr)`, gridTemplateColumns: `repeat(${sideLength}, 1fr)`, padding: "20%", paddingTop: "0"}}>
{ rows.map((row, index) => <Row key={row.toString() + index} row={row} rIndex={index} handleMove={handleMove} />)}
</div>
);
};
export default GameBoard;
TicTacToe mostly handles the game logic
import {useState} from "react";
import GameBoard from "./GameBoard";
const TicTacToe = () => {
const [winner,setWinner] = useState(null)
const [moves,setMoves] = useState<number[][]>([]);
const handleMove = (rIndex,cIndex) => {
setMoves((old) => {
return [...old, [rIndex,cIndex]];
});
};
return (<div>
<GameBoard moves={moves} handleMove={handleMove} />
</div>)
};
export default TicTacToe;
When I test it in the browser, clicking squares alternately adds "X"s and "O"s as expected. But in the following test, I can't confirm this:
test("symbols alternate on moves", ()=>{
render(<TicTacToe />);
const beforeSquares = screen.getAllByTestId('square');
const beforeOne = beforeSquares[0]; // X
const beforeTwo = beforeSquares[1]; // O
const beforeThree = beforeSquares[2]; // X
userEvent.click(beforeOne);
userEvent.click(beforeTwo);
userEvent.click(beforeThree);
const afterSquares = screen.getAllByTestId('square');
const afterOne = afterSquares[0]; // X
const afterTwo = afterSquares[1]; // O
const afterThree = afterSquares[2]; // X
waitFor(()=>{
expect(afterOne).toHaveTextContent('X'); // test also passes if I change this to 'Z'
expect(afterTwo).toHaveTextContent('O');
expect(afterThree).toHaveTextContent('X');
});
});
As indicated in the comments, the expect with X anywhere on the screen finds something -- an element with data-testid of square, but when I query for these elements and check their textContent, they are all empty! Why isn't this working for me?

Dynamically updating dropdown menu in React

Using fetch, I want to dynamically populate the City material-ui dropdwon (Select) when I select a value from the State dropdown, but could not do so. When I do the same without using the fetch, it works fine. I think the problem is with the promise being returned by the fetch call. There is no problem in the fetch call as I can see the list of cities in return. Please suggest how to do it.
import React from 'react';
import { createStyles, makeStyles, Theme } from '#material-ui/core/styles';
import InputLabel from '#material-ui/core/InputLabel';
import FormHelperText from '#material-ui/core/FormHelperText';
import FormControl from '#material-ui/core/FormControl';
import {Select, MenuItem} from '#material-ui/core';
import './App.css';
export function getStates() {
return [
{name: 'California', id: "1"},
{name: 'New York', id: "2"},
]
}
function Home() {
const useStyles = makeStyles((theme: Theme) =>
createStyles({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}),
);
const [State, setState] = React.useState([]);
const [cities, setCities] = React.useState([]);
const selectStyle = makeStyles(theme => ({
root: {
textDecoration: 'none',
color: 'red',
alignItems: 'center',
fontWeight: "bold",
display: "flex",
justifyContent: "space-around",
fontSize: 18,
margin: 0,
'&:hover': {
textDecoration: 'none'
}
},
}));
function getCities() {
var s = '' // JSON body goes here
const fetchData = async () => {
const cities = [];
try {
const res = await fetch('http://127.0.0.1:8080',
{
method : "POST",
headers: {"content-type": "text/plain"},
body: s
}
);
const data = await res.json();
console.log("state response status: " + res.status)
for(var key in data.cities) {
cities.push({id: key, name: data.cities[key]})
}
return cities;
}
catch (err) {
console.log("Fetch Exception: " + err)
}
}
const cities = fetchData();
return cities;
}
const handleStateChange = (event: React.ChangeEvent< { value: unknown} >) => {
setState(event.target.value);
const r = getCities();
setCities([r]);
}
const fixed_states = getStates();
const classes = useStyles()
const selectClass = selectStyle()
return (
<div className="main-select">
<container>
<FormControl required className={classes.formControl}>
<InputLabel id="sel">State</InputLabel>
<Select labelId="state_select_labelid" id="state_select_id" name="state_select_name" onChange={handleStateChange} className={selectClass.root}>
{fixed_states.map(({id, name}, index) => (
< MenuItem key={id} value={name}>
{name}
</MenuItem>
)) }
</Select>
<FormHelperText></FormHelperText>
</FormControl>
<FormControl required className={classes.formControl}>
<InputLabel id="city_input_label_id">City</InputLabel>
<Select labelId="city_select_labelid" id="city_select_id" name="city_select_name">
{cities.map(({id, name}, index) => (
< MenuItem key={id} value={name}>
{name}
</MenuItem>
))}
</Select>
<FormHelperText></FormHelperText>
</FormControl>
</container>
</div>
);
}
export default Home;
You code:
const handleStateChange = (event: React.ChangeEvent< { value: unknown} >) => {
setState(event.target.value);
const r = getCities();
setCities([r]);
}
but getCities return array of cities and then you set array cities in state like array of array.
So just update argument in setCities row to
const handleStateChange = (event: React.ChangeEvent< { value: unknown} >) => {
setState(event.target.value);
const r = getCities();
setCities(r);
}

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]);

Dropping Over a Component inside nested Drop Targets giving error

Here is my Container Class
Code on Sandbox
`import React, { Component } from "react";
import { DropTarget } from "react-dnd";
import Box from "./Box";
class Container extends Component {
state = {
Boxes: [
{ left: 60, top: 30, text: "ITEM_1" },
{ left: 100, top: 70, text: "ITEM_2" }
]
};
render() {
const { connectDropTarget } = this.props;
return connectDropTarget(
<div
className="container"
style={{ width: "100%", height: "100vh", background: "yellow" }}
>
{this.state.Boxes.map((box, index) => {
return (
<Box
id={index}
key={index}
left={box.left}
top={box.top}
text={box.text}
moveBox={this.moveBox}
/>
);
})}
</div>
);
}
moveBox(id, left, top) {
const allBoxes = this.state.Boxes;
const singleBox = this.state.Boxes[id];
singleBox.left = left;
singleBox.top = top;
const newBox = allBoxes.filter((box, index) => index !== id);
newBox.push(singleBox);
this.setState({ Boxes: newBox });
}
}
export default DropTarget(
"items",
{
// Spec Object Started
drop(props, monitor, component) {
const item = monitor.getItem();
const delta = monitor.getDifferenceFromInitialOffset();
const left = Math.round(item.left + delta.x);
const top = Math.round(item.top + delta.y);
component.moveBox(item.id, left, top);
}
}, //Spec Oject Ended Here
(connect, monitor) => ({
connectDropTarget: connect.dropTarget()
})
)(Container);
`
And Here is my Box Class
import React, { Component } from "react";
import { DragSource, DropTarget } from "react-dnd";
import flow from "lodash/flow";
let whichDragging = "items";
class Box extends Component {
state = {};
render() {
const { left, top, text, connectDragSouce, connectDropTarget } = this.props;
return connectDragSouce(
connectDropTarget(
<div
style={{
width: "20%",
border: "2px dotted black",
margin: "auto",
position: "relative",
top: top,
left: left
}}
>
{text}
</div>
)
);
}
}
export default flow(
DragSource(
whichDragging,
{
beginDrag(props, monitor, component) {
console.log(component);
const { left, top, text, id } = props;
return {
left,
top,
text,
id
};
}
},
(connect, monitor) => ({
connectDragSouce: connect.dragSource()
})
),
DropTarget(
whichDragging,
{
drop(props, monitor, component) {
whichDragging = "nested";
const item = monitor.getItem();
const delta = monitor.getDifferenceFromInitialOffset();
const left = Math.round(item.left + delta.x);
const top = Math.round(item.top + delta.y);
console.log("Logging");
console.log(component);
// whichDragging = "items";
}
},
(connect, monitor) => ({
connectDropTarget: connect.dropTarget()
})
)
)(Box);
Simple Dragging Dropping Working fine but when i drop item_1 over item_2 or vice versa i got error and my Component in drop shows DragDropContainer in console.log i want to get the id|key of component over which one component is dropped and not able to find any solution since 2 days any help will be appriciated.

Resources