Unable to align ListItem text - javascript

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>

Related

Align multiple items based on the row location

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

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

What is the better way to structure components' props?

I'm now testing some Material-UI components and can't understand 1 moment. For example, in List component. Why do they use syntax like this?
<List component="nav">
<ListItem
button
selected={selectedIndex === 0}
onClick={(event) => handleListItemClick(event, 0)}
>
<ListItemIcon>
<InboxIcon />
</ListItemIcon>
<ListItemText primary="Inbox" />
</ListItem>
</List>
it seems to me that you can just use this approach:
<List component="nav"
items=[
{
icon: 'inbox',
text: 'Inbox',
onClick: () => handleListItemClick()
}
]
/>
Оr you can also use render props.
What makes their approach more convenient? after all, they clearly chose it for some reason
Although I'm not familiar with their style, the example seems simple to follow maybe for presentation purposes. For real use application usage you may want to do your array style example.

Material-UI - How to render something on top of the AppBar?

I'm developing a React web app using the Material-UI framework. I've now come to a point where I want to render something on top of the AppBar, but from a different file.
My app is structured like this:
Main.js - contains the AppBar and react-router
Various views or "pages" which are loaded by react-router as children of Main.js
Various components that are rendered by these pages.
You can see what I'm trying to achieve below.
If it helps, here is the code for the AppBar, note; I have also tried with "static" position.
<AppBar position="fixed">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="menu"
onClick={handleClick}>
<MenuIcon/>
</IconButton>
<Typography variant="h4" className={classes.title}>
<Link href="/" variant="h4" color="inherit">Site Name</Link>
</Typography>
</Toolbar>
<div>
<Menu
id="Menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}>
<MenuItem onClick={handleClose}>
// SOME MENU ITEM
</MenuItem>
</Menu>
</div>
</AppBar>
And the page where I am trying to render the widget. For now I am just using a Typography component as a placeholder. My understanding is that I need to set the Z index of the div that this widget is wrapped in to elevate it, however, I assume that it is only relative to other components within this view, and not also the AppBar as that is coming from elsewhere?
<div>
<div
style={{
height: 20,
backgroundColor: "yellow",
position: "relative",
zIndex: 10
}}>
<Typography component="h3" variant="h3">Widget Placeholder</Typography>
</div>
<Toolbar></Toolbar> // Empty toolbar is used to push all the other content down below the AppBar when it's position is set to fixed
// other content from this page
</div>
Code sandbox: https://codesandbox.io/s/goofy-feather-cf1kd?file=/src/App.js
Thanks :)

Making a react component clickable

I have a functional REACT component, code is as follows
const MobileListing = (props) => {
function handleClick() {
console.log('in cardClick');
}
return (
<div>
<Row>
<Card onClick={() => handleClick()} style={{cursor : 'pointer'}} >
<Card.Img variant="top" src="holder.js/100px180" />
<Card.Body>
<Card.Title>Card Title</Card.Title>
<Card.Text>
Some quick example text to build on the card title and make up the bulk of
the card's content.
</Card.Text>
<Button variant="primary">Go somewhere</Button>
</Card.Body>
</Card>
</Row>
</div>
);
}
export default MobileListing;
I want to make the entire card clickable. I read through a post on stack overflow Making whole card clickable in Reactstrap which talks about using an anchor tag, but that doesn't work for me.
Can someone help me understand what I am doing wrong?
A card looks like this on my site and I want to make the whole card clickable.
You can use the onClick either on the top-level div element for this, or, in case there would be more cards inside the Row you can wrap each with a div and give it the onClick, property.
such like:
<div>
<Row>
<div onClick={handleClick}>
<Card style={{ width: '18rem', cursor : 'pointer' }} >
<Card.Img variant="top" src="holder.js/100px180" />
<Card.Body>
<Card.Title>Card Title</Card.Title>
<Card.Text>
Some quick example text to build on the card title and make up the bulk of
the card's content.
</Card.Text>
<Button variant="primary">Go somewhere</Button>
</Card.Body>
</Card>
</div>
</Row>
</div>
It is better to wrap it around with an anchor tag because clickable things should be links if they go to places, and should be buttons if they do things.
Using click handlers with other things just make things inaccessible.

Categories

Resources