Align multiple items based on the row location - javascript

I am using 2 internal company related components Row and Column which I can't change but they both take in style property thus could pass in any css styling.
Note that I have to use these components for other purposes.
This is currently how it looks which is incorrect.
Can see 2 issues.
Due to product subtile on the first, the second one mis aligned.
Due to more text on the description on the second, again mis aligned.
I am looking to achieve this.
Is there a way to do this. Was attempting with flex box but due to the way the divs are nested, struggling with it.
It would work if I switch it around and create by row.
Meaning don't create a column one short like this.
But go for row by row like this.
But I can't do this due to accessibility. The screen reader should read column by column. But ends up reading row by row if I do this.
Example: Product Title 1 Product Title 2 and then coming back to Cost $1000 switching between the 2 products which is incorrect.
Thus I wish to stick with creating 1 column at a time as what I have now but how can I achieve the desired row alignment? Please help. Thanks.
My code.
This is the main Row for both items.
<Row style={'I can pass styling here'}>
{products}
</Row>
This is where I am looping and creating column by column for the products.
const products = productsList.slice(0, 3) // screenshot above shows 2 but can go up to 3
.map((p, index) => (
<Column style={'I can pass styling here'}>
{/* The image, title and subtitle all come from here */}
<SelectedProduct/>
{/* price description section*/}
{price(p, index)}
{/* button and links here.
These are not having alignment issues. Fixing subtitle and description alignments should take care of this
*/}
{links(p)}
</Column>
));
Condensed SelectedProduct component.
const SelectedProduct = () => {
return (
<div className={styles.product}>
<div style={{ position: 'relative' }}>
<div>
<Link to={redirectTo}>
<Art src={url} />
</Link>
</div>
<TrackedRemoveButton type="button"/>
</div>
<Typography>
{title}
</Typography>
<Typography>
{subtitle}
</Typography>
</div>
);
};
styling in SelectedProduct
.product {
display: flex;
flex-direction: column;
align-items: center;
}
Condensed price component.
const price = (p) => {
return (
<div>
<Typography>
<span
dangerouslySetInnerHTML={{
__html: p.content,
}}
/>
</Typography>
</div>
);
}

This is a surprisingly difficult problem. Here is my solution: https://codepen.io/dlwalsh/pen/gOdayNQ
It uses flexbox with column direction. The important bits are:
The parent declaration align-items: stretch so that each item extends to the full height.
The button declaration margin-top: auto so that it (and everything beneath it) anchors to the bottom.
It works, but it relies on everything else having a fixed height. i.e.
The title and subtitle are always one line
A blank subtitle inserted when missing
There are always exactly two product links

Related

How to get the title to the next line in a card?

I an working on Card from antd. I want to get the rest of title to the next line if it is long. For eg, title is displayed as "This title needs to go to ne..." but I want it to be displayed in two lines. "This title needs to go to" in the first line and "next line" in the next line. I know we can make use of inline size to get to the next line but I don't want to make use of pixel as width since I want to make it interactive. This is the code I have written :
<Row gutter={24}>
<Col xs={24} md={10}>
<Card
title={<span>This title name should go to next line if instead of displaying ...</span>}
bodyStyle={{ paddingTop: 5 }}
>
<p>Card description</p>
</Card>
</Col>
</Row>
How do I get it to the next line using inline size and make it interactive?
You can simply use break in your span tag.
<Card
title={<span> first line <br/> second line</span>}
bodyStyle={{ paddingTop: 5 }}
/>
or target card header using css
.ant-card-head-title {
text-overflow: unset !important;
white-space: unset !important;
}

How can I componentize TextFields into a function rather than writing multiple TextFeilds?

There is a lot to read here, but there is no other way to explain the issue I have.
I have four files, App.js, Intakes.js, IntakeDetails.js and Sizing.js. I start on the Intakes page where the user is presented with a table of data. The user clicks on a row and is taken to IntakeDetails. In IntakeDetails, there are four MUI tabs, one of which is Sizing.
The user never actually goes to a Sizing page. They only get to IntakeDetails. From IntakeDetails, the user can view, edit, and create data based on what tab they are in. If the user wants to create or update Sizing data, they navigate to the sizing tab and click the edit icon on the row of their choice from the Sizing table. The Dialog then pops up and its TextFields are populated with the data from the row the user clicked.
Sizing.js is 600+ lines long. 211 lines in this file are taken up by the MUI dialog which displays the data from the table row the user has clicked. The dialog is so long because of 19 TextFields. I want to make a short function with a parameter for id, value and label. This way I wont need to have lots of multiline TextFields. All of the TextFields in the Dialog take up 8 lines. With a function, this could be just one or two lines.
I have made a function to shorten the file previously, but it introduces a new problem. If I have a TextField that is populated with the word 'Hello', and I edit it, the Dialog disappears, reappears, and focus is lost on the TextField I edited, but, the change I made is persistent. I can only enter or remove one character at a time before having to click on the TextField again to enter another. I can copy and paste full words and sentences at once, but again the Dialog disappears and comes back.
I can't use .map because my data is not divided into groups or objects. It is all one object and needs to be presented in the dialog in a specific order, which is why they are hardcoded. When I type in a TextField, there is a long delay between the time I press a key on the keyboard and the time the character appears in the TextField. This delay gets longer when I type faster.
The return in IntakeDetails is here:
import Sizing from "./Sizing";
...
return (
<div class="aspectwrapper">
<div class="content">
<Container>
<Paper>
<Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs value={value} onChange={handleChange}>
<Tab label="Intake Details" {...a11yProps(0)} />
<Tab label="Sizing" {...a11yProps(1)} />
</Tabs>
</Box>
<TabPanel value={value} index={0}>
** Intake Details Stuff **
</TabPanel>
<TabPanel value={value} index={1}>
<Sizing />
</TabPanel>
</Box>
</Paper>
</Container>
</div>
</div>
)
The return in Sizing. There are 19 TextFields, all structured as seen below. There are also buttons in a <DialogActions> tag which I have not included here.
const onTextChange = (e) => {
const id = e.target.id;
var value = e.target.value;
setSingleSizing({ ...singleSizing, [id]: value });
};
...
return(
<div id="sizing-container">
<Dialog open={open} onClose={handleClose} maxWidth={"xl"}>
<DialogTitle id="form-dialog-title">Edit estimation</DialogTitle>
<DialogContent>
<Box>
<TextField
id="SizingComments"
value={singleSizing?.SizingComments}
label={"Estimation Comments"}
onChange={onTextChange}
variant="outlined"
style={{ margin: "1em", minHeight: "1em", minWidth: "15em" }}
/>
</Box>
</Box>
</DialogContent>
</Dialog>
</div>
)

D-flex makes bootsrtap grid system broke

I create a dashboard with reactJs and react bootstrap. Due to the different size of the card on my dashboard, it's resulting the gap on my dashboard. This is the screenshot :
I want to fill the gap on my dashboard. According to the bootstrap flex documentation, I used d-flex align-items-stretch to fill the gap. Like this :
<Row>
<Col lg="6" md="6" sm="12" className="d-flex align-items-stretch"> //I placed it on Col
<FrequentUsers />
</Col>
<Col lg="6" md="6" sm="12" className="d-flex align-items-stretch">
//Other content
</Col>
</Row>
Placing the d-flex align-items-stretch on the <Col> tag is the
only way that I found worked in my case. If I place it in <Row> tag
or in <div> tag as a container outside it, it didn't work.
The result is the y-axis stretched well as I expected, but the x-axis suddenly shrink :
So I manage my grid layout to make it wider. The grid layout is still working but it didn't affecting the card, it is only affecting the gap like there is a invisible container in it. So I'm assuming that the grid system at this point is "broken"
I'm guessing that this is because the d-flex. But as I read the documentation, it should've instead make the content fully extended to the side. Please check it on the documentation here
Based on #ChewySalmon's comment. I try to adjusting flex-basis on my card. The reason I do it directly on my card is because as I provided in a code sample in my question above, I stretched my item on a <Col> tag, which is stretch the conten vertically (as my screenshoot shown above). So I need to do it on my card (also because this is the only way that worked in my case), so it stretched horizontally. And it work perfectly. Here is the implementation code :
<Card style={{flexBasis: "100em"}}>
//my content
<Card>
I use 100em because it's the only way besides 100px that worked for me. I hard coded it like that because the value is the same in all card, which is 100em. But I recommend you using props in JSX attribute. Hope that help you who have a same problem with me in the future. Thanks to #ChewySalmon.

Unable to align ListItem text

I have this material-ui list:
<List dense>
{this.state.issues.map((item, i) => {
return <Link target="_blank" to={item.issue_url} key={i}>
<ListItem button>
<ListItemText primary={item.issue_state}/>
<ListItemSecondaryAction>
<IconButton>
<ArrowForward/>
</IconButton>
</ListItemSecondaryAction>
</ListItem>
</Link>
})
}
</List>
issue_state is obtained from MongoDB. Can I add another column to my list showing another field from the database? I tried:
<ListItemText primary={item.issue_state}/>
<ListItemText primary={item.issue_title}/>
This displays what I want but the issue_title test is centered. I'd like it left aligned. Can this be done?
ListItemText component renders with the following CSS style that allows it to be flexible to grow and shrink according as the width and height of its content.
flex: 1 1 auto;
Its ancestor ListItem component renders as an inline-flex.
AFAICT, the results you're looking to achieve can't be done without overriding these styles. Not to worry, there are other ways to go that uses available APIs exposed in the component.
Never mind that the name for the component seems to be misleading that its usage is specific for rendering text in the list item.
A closer look in the ListItemText component API documentation shows that the primary property is of the node type.
That implies that the ListItemText can be used to render string, function, and React.Element in a manner similar to the snippet below.
<ListItemText primary={<div>Foo<br/>Bar<br/>Baz</div>} />
There is also the secondary property that renders the elements with textual emphasis.
<ListItemText primary="Foo" secondary={<div>Bar<br/>Baz</div>} />
If you need more control over the children of the ListItemText, the API allows for the flexibility to write it this way
<ListItemText>
<Typography variant="subheading">Foo</Typography>
<Typography variant="body1" color="textSecondary">Bar</Typography>
<Typography variant="body1" color="textSecondary">Baz</Typography>
</ListItemText>

How to progressively render react components?

I'm working with lists that will likely be in the range of 500 up to maybe 5000 items. Each item in the list will show as a component, like so:
List
render() {
return (
<div className="ItemList">
<Info items={this.props.items} />
<ul>
{this.props.items.map( item =>
<Item item={item} key={item._id} refresh={this.props.refresh} />
)}
</ul>
</div>
);
}
Item
render() {
var item = this.props.item;
return (
<li onClick={() => this.setState({showInfo: !this.state.showInfo})}
className="Item">
<h3 className={this.state.showInfo ? "item-title-bar active" : "item-title-bar"}>
<div>
<div className="item-category">
{item.category}
</div>
<div className="item-name">
{item.name}
</div>
</div>
</h3>
{this.state.showInfo &&
<ItemInfo item={this.props.item} refresh={this.props.refresh} />
}
</li>
);
}
Once one of these lists gets up to around 1000 items, it's noticeably slow when I click to show a different list. Perf tools are showing me 90-150 ms for displaying this list at 1000 or 2000 items. Not sure I can get around that as long as I'm rendering them.
So, what I'm trying to do:
Can I let the initial items update, then render others in the background, while the app remains responsive?
How can I show initial items, then load more as the user scrolls down the page?
If neither option works, I'll probably try to load a few, then add a show more or show all button at the bottom of the list. Want to make this as seamless as possible though, open to other suggestions as well.
react-virtualized would be my first choice when dealing with a virtual list. Lot of examples here: https://bvaughn.github.io/react-virtualized/#/components/List
Pretty simple if you know the heights of the items ahead of time, but can use the CellMeasurer component if you don't.

Categories

Resources