changing width of a box inside map function in react js - css

I want to change the size of one of the boxes inside the map function. If all boxes are size of 10px, I want one of the boxes "=" to double the length of other boxes.
CSS:
.display-keys {
display: grid;
grid-template-columns: 10px;
}
.display-equal {
display: grid;
grid-template-columns: 20px;
}
React:
const Keys = ({calcKeys})=>(
<div>
{calcKeys.map(item=>
{item.key} !== "=" ?
<button className="display-keys">{item.key}</button> :
<button className="display-equal">{item.key}</button>
)}
</div>)
class App extends React.Component {
constructor(props) {
super(props);
this.state={
calcKeys:[{"key": "AC"},{"key": "CE"},{"key": "±"},{"key": "="}]
};
render(){
return(
<div className="display-container">
<Keys calcKeys={this.state.calcKeys}/>
</div>
)
}
ReactDOM......

Firstly, You should return the result of the map function
{calcKeys.map(item=>{
return (item.key !== "=") ?
<button className="display-keys">{item.key}</button> :
<button className="display-equal">{item.key}</button>
}
)
}
next:
The grid-template-columns CSS property defines the line names and track sizing functions >of the grid columns.
In your CSS, use width for the length of boxes
.display-keys {
width: 40px;
}
.display-equal {
width: 80px;
}
you don't need put display: grid inside those files. I think you already have it in .display-container
and finally, you can check this codesandbox out.

Something like this should work:
{calcKeys.map((item)=>{
if(item.key !== '='){
return <button className="display-keys">{item.key}</button>
}
return <button className="display-equal">{item.key}</button>
})
}

Related

React.js & styled-components - Styled Input with (the illusion of ) Element inside it

so what i'm trying to do is to create an styled input that seem to have a fixed text (div / children / etc...) inside it.
one image can be self explenatory so this is how it looks like right now:
it seems simple, and the basic idea i quite is:
i got some Wrapper component that has 2 children - the input itself & some element.
like so:
const Input = (props: InputProps) => {
return (
<Wrapper>
<InputStyled {...props} />
<InnerElement>cm</InnerElement>
</Wrapper>
);
};
export default Input;
So where is the problem?
The problem is when i'm trying to set width to this component.
It destroys everything.
is looks like so:
so the wrapper should get a width prop and keep the input and the text element inside of it.
here is a codesandbox i created:
https://codesandbox.io/s/reactjs-input-with-element-inside-forked-2kr6s?file=/src/App.tsx:0-1795
it'll be nice if someone understand what i'm doing wrong.
here are some files:
Input.tsx
import React, { InputHTMLAttributes, CSSProperties } from "react";
import styled from "styled-components";
export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
style?: CSSProperties;
label?: string;
value: string | number;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
text?: string;
isDisabled?: boolean;
hasError?: boolean;
errorLabel?: string | Function;
placeholder?: string;
width?: string;
}
const defaultProps: InputProps = {
text: "",
onChange: () => null,
value: ""
};
const Wrapper = styled.div<Partial<InputProps>>`
outline: 1px dashed red;
box-sizing: border-box;
justify-self: flex-start; // This is what prevent the child item strech inside grid column
border: 2px solid lightblue;
background: lightblue;
border-radius: 8px;
display: inline-flex;
align-items: center;
max-width: 100%;
width: ${({ width }) => width};
`;
const InputStyled = styled.input<Partial<InputProps>>`
box-sizing: border-box;
flex: 1;
outline: 1px dashed blue;
padding: 8px;
border: none;
border-radius: 8px;
max-width: 100%;
:focus {
outline: none;
}
`;
const InnerElement = styled.div`
outline: 1px dashed green;
box-sizing: border-box;
${({ children }) =>
children &&
`
padding: 0 8px;
font-size: 13px;
`};
`;
const Input = (props: InputProps) => {
return (
<Wrapper width={props.width}>
<InputStyled {...props} />
<InnerElement>{props.text}</InnerElement>
</Wrapper>
);
};
Input.defaultProps = defaultProps;
export default Input;
App.tsx
import * as React from "react";
import "./styles.css";
import Input from "./Input";
import styled from "styled-components";
const ContainerGrid = styled.div`
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 50px;
`;
export default function App() {
const [value, setValue] = React.useState("");
const handleChange = (e: any) => {
setValue(e.target.value);
};
const renderInputWithElement = () => {
return (
<ContainerGrid>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"60px"} // Play with this
text="inch"
/>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"110px"} // Play with this
text="cm"
/>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"200px"} // Play with this
text="mm"
/>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"100%"} // Play with this
text="El"
/>
<Input
placeholder="input with element inside"
value={value}
onChange={handleChange}
width={"100%"} // Play with this
/>
</ContainerGrid>
);
};
return (
<div className="App">
<h1>StyledCode</h1>
<h3>Input with an element inside</h3>
<p>
This is kind of an illusion since input cannot have child element inside
of it really.
</p>
<hr style={{ marginBottom: "32px" }} />
{renderInputWithElement()}
</div>
);
}
I Fixed it for you:
https://codesandbox.io/s/reactjs-input-with-element-inside-forked-h2het
First problem was that your were setting the same width to Wrapper and to InputStyled (by passing ...props) Then things get messy. Obviously, both parent and children which has some other element next to it can't have same width. InputStyled's won't be rendered with width you give it, but lesser, as it's being stretched to left by InnerElement.
If you need to pass it all the props, including the width, than you can just remove that width prop by setting width to unset
<InputStyled {...props} width="unset" />
However, there was another issue with padding interfering with width calculation. See answer to another question:
According to the CSS basic box model, an element's width and height
are applied to its content box. Padding falls outside of that content
box and increases the element's overall size.
As a result, if you set an element with padding to 100% width, its
padding will make it wider than 100% of its containing element. In
your context, inputs become wider than their parent.
You can go along with solution there. However, the one simple solution is to use width lesser than your padding, so width: calc(100% - 16px). This does the trick.
So i've found the answer, and its quite simple.
since the browser initializes an input with a width, it cause problems
with the flexbox behavor - the input element can't shrink below its default width and is > forced to overflow the flex container.
So i added min-width: 0 to InputStyled.
thats it.
#justdv thanx for your answer, you right about the width being on the wrong place, i fixed it but the sandbox wasnt updated. i missed that.
thanx anyway for your time :)
here is my fixed sandbox:
https://codesandbox.io/s/reactjs-input-with-element-inside-forked-44h8i?file=/src/Input.tsx
Thanx again for reading.

Print MaterialUI Dialog fullscreen

I am new to React and Material-UI and I want to print my current dialog.
The problem is that I cannot find a way to maximize my Dialog for priting (set to fullScreen) without doing it in the Browser, too. So I basically want a smaller Dialog in my Browser and for the Dialog the maximal size.
Here is my basic code in TSX:
import React, { Component} from 'react';
import { Button, Dialog } from '#material/core';
export default class MUITester extends Component {
render(){
return (
<Dialog fullScreen={false}>
<div>
<Button onClick={() => window.print()}>
PRINT
</Button>
</div>
</Dialog>
);
}
And the corresponding css file:
#media print {
.print {
fullScreen=true;
color: blue;
}
}
Can I solve it using css? Or do I have to use React/Material-UI?
I solved it! Change the classes of Dialog:
<Dialog classes={{paperFullScreen: "prePrint printDialog"}} fullScreen>
Here my css:
.prePrint {
height: auto !important;
max-width: 600px !important;
}
/*Print Dialog*/
#media print {
.printDialog {
max-width: 100% !important;
}
}
You can set the width of your dialog like this:
<Dialog fullWidth={true} maxWidth='md'>
<div>
<Button onClick={() => window.print()}>
PRINT
</Button>
</div>
</Dialog>
As given in the Documentation
For printing div, which is inside dialog, use below code, and add css also
import React, { Component} from 'react';
import { Button, Dialog } from '#material/core';
export default class MUITester extends Component {
render(){
return (
<Dialog classes={{paperFullScreen: "prePrint"}} fullScreen>
<div id="DialogPrint">
some text some text , some paragraph and so on
</div>
<div >
<Button onClick={() => window.print()}>
PRINT
</Button>
</div>
</Dialog>
);
}
}
add below code in css
.prePrint {
height: auto !important;
max-width: 600px !important;
}
/*Print Dialog*/
#media print {
body * {
visibility: hidden;
}
#DialogPrint,
#DialogPrint * {
visibility: visible;
}
#DialogPrint {
position: absolute;
left: 0;
top: 0;
}
}
I was looking for a full-screen Dialog on mobile and a simple dialog for desktop and the below example resolved my issue, please take a look if helps.
import useMediaQuery from '#mui/material/useMediaQuery';
function MyComponent() {
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down('md'));
return <Dialog fullScreen={fullScreen} />;
}
You can check demo on MUI official documentation.
You just need to add fullScreen flag to modal component in order to achieve full screen.
Like below
<Dialog fullScreen open={open} onClose={handleClose} TransitionComponent={Transition}>
And if you don't want to use fullScreen, simply remove that fullScreen flag and don't need to use CSS here.

react wait for another component to finish rendering

I have the following situtation:
2 components A and B.
A is above B in the page layout.
I wish to calculate B height css rule dynamically using it's top.
B's top is affected by A because A is rendered above it. I attached a reference to B and then apply it style by calculating the bounding rect of the ref and calculating the desired height from the top.A problem occurs when component A is taking more time to fully render than component B because A loads images that takes a bit more time to load making B's top to shift a after it was already rendered so the calculating of the height in the function needs to be called again somehow after A was fully rendered but I don't wanna make B coupled to A just because it renders before it, what can I do to solve this issue?
You can solve it using Css flexbox, check code snippet bellow.
(function () {
var loadImgBtn = document.getElementById('load-image-btn');
var loadedImg = document.getElementById('loaded-image');
loadImgBtn.addEventListener('click', function () {
loadedImg.style.display = 'block';
});
})();
.flexbox {
display: flex;
flex-direction: column;
align-items: stretch;
min-height: 350px;
}
#loaded-image {
display: none;
}
#first-block {
background: green;
}
#second-block {
background: red;
flex-grow: 1;
}
<div class="flexbox">
<div id="first-block"> Component A
<img id="loaded-image"
src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</div>
<div id="second-block">Component B</div>
</div>
<button id="load-image-btn">Load Image</button>
If you want to calculate it programmatically you can use ref or forwardRef if you need to pass ref further down something like this
const ComponentA = React.forwardRef((props, ref) => (
<div ref={ref} className="componentA">
{props.children}
</div>
));
const ComponentB = React.forwardRef((props, ref) => (
<div ref={ref} className="componentB">
{props.children}
</div>
));
class App extends React.Component{
constructor(props){
super(props);
this.refA = React.createRef();
this.refB = React.createRef();
}
componentDidMount(){
console.log(this.refA.current.clientHeight,this.refB.current.clientHeight);
}
render(){
return (
<div className="App">
<ComponentA calculatedHeight={componentAHeight} ref={this.refA} >Component A</ComponentA>
<ComponentB calculatedHeight={componentBHeight} ref={this.refB} >Component B</ComponentB>
</div>
);
}
}
You can do it using findDOMNode too (it is depricated in strict mode). react-sizeme might be helpfull as well.

Can't get buttons to wrap to new line instead of overflowing container

I couldn't get a JSFiddle to work properly with React and some other dependencies, so I hope the link to this Github repo is sufficient for demonstrating the issue:
https://github.com/ishraqiyun77/button-issues/
Basically, a group of buttons is rendered and they should be auto-widened to fill white space and take up the whole row. This works in Chrome, Edge, Safari, and Firefox. It looks like this:
This isn't happening in IE. I've been messing with it for hours and haven't made much progress:
Here is the code, although could clone the repo I posted above:
// component.jsx
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import {
Button,
Col,
Modal,
ModalBody,
ModalHeader,
Row
} from 'reactstrap';
import styles from '../assets/scss/app.scss';
class TestPrint extends Component {
constructor(props) {
super(props);
this.state = {
modal: false,
}
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
modal: !this.state.modal
})
}
renderContent() {
let buttons = [];
for (let i = 1; i < 50; i++) {
buttons.push(
<Col key={i}>
<Button
key={i}
className='cuts-btn'
>
{i} - Test
</Button>
</Col>
);
};
return buttons;
}
render() {
return (
<div>
<Button
style={
{
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}
}
onClick={this.toggle}
>
Open Modal for Buttons
</Button>
<Modal
size='lg'
isOpen={this.state.modal}
toggle={this.toggle}
className='results-modal'
>
<ModalHeader toggle={this.toggle}>
Button Issues
</ModalHeader>
<ModalBody>
<div className='results-bq-cuts'>
<Row>
{this.renderContent()}
</Row>
</div>
</ModalBody>
</Modal>
</div>
)
}
}
ReactDOM.render(<TestPrint />, document.getElementById('app'));
.results-modal {
max-width: 1200px;
.modal-content {
.modal-body {
margin-left: 13px;
margin-right: 13px;
.results-bq-cuts {
width: 100%;
.col {
padding:2px;
}
.cuts-btn {
font-size: 11px;
padding: 3px;
width: 100%;
box-shadow: none;
}
// .col {
// padding: 2px;
// display: table-cell;
// flex-basis: 100%;
// flex: 1;
// }
// .cuts-btn {
// font-size: 11px;
// padding: 3px;
// width: 100%;
// box-shadow: none;
// }
}
}
}
}
I have all of the <Button> wrapped in <Col> because that should be what is filling the white space by increasing the size of the button.
Thanks for the help!
IE11 doesn't like working out the width of flex items. If you add flex-basis: calc( 100% / 24 ); to .col it works :) Obviously use any width you want, but what I've given replicates the 21 boxes on one line. But essentially flex-basis needs a defined width to work.
​
Or add an extra class to each element (such as col-1 ) This'll also achieve the same thing.

Reactjs and SCSS - how to write height: selfheight x 2

I want to double the height of the div every time it is clicked.
I am thinking to apply a additional CSS class to a div when ever I click a button. The CSS concept will be like:
#divToBeDoubled {
height: 100px;
&.doubleHeight{
height: selfHeight*2
}
}
How can I achieve this by using Reactjs and SCSS?
I think if you want to change a css value with the component state, you need to move the property you want to change in you component or use JSS...
to move the property in the render, you can do this :
class MyComponent extends React.Component{
state = {
divHeight : 100
}
doubleSize = ()=>{
this.setState({ divHeight : this.state.divHeight * 2 })
}
render() {
const style = {
height: this.state.divHeight
};
return (
<div style={style} onClick={this.doubleSize}>Content</div>
);
}
}
If using sass. You can use this, and toggle class in JSX onclick event.
$height: 100px;
.normal {
height: $height;
}
.double {
height: $height * 2;
}

Resources