I am working on a simple app to display heart rate, blood glucose levels and several other measurements. I am working in React and Redux, and using Materials-UI for UI.
To display these two numbers, I am creating a component that will be on each half of the screen. Under each number, I will have a set of tabs to switch within views of the component.
I want to resize the tabs to be the correct size, but it is too large currently and takes up too much space. How can I resize the tabs to be smaller. I have the code below for creating tabs and have read through this and this but am unsure on how to do this.
I attempted use withStyles(styles) as shown below, but it doesn't work properly.
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import { withStyles } from '#material-ui/core/styles';
import Grid from '#material-ui/core/Grid';
const BottomTab = ({}) => (
<Grid item direction="column" alignItems="center" justify="center">
<Tabs
value={0}
indicatorColor="primary"
textColor="primary"
variant="fullWidth"
>
<Tab label="Current" />
<Tab label="Set New" />
<Tab label="Alarm" />
</Tabs>
</Grid>
);
const styles = {
tab: {
width: '10', // a number of your choice
}
};
export default withStyles(styles)(BottomTab);
and the following code block is where I call the BottomTab.
interface Props {
labelId: string,
value: number
}
const Knob = ({labelId, value}: Props) => (
<Grid item container direction="row" alignItems="center" justify="center">
<Grid item xs>
<ValueDisplay labelId={labelId} value={value} />
</Grid>
<Grid item container direction="column" alignItems="center" justify="space-evenly">
<BottomTab />
</Grid>
</Grid>
)
export default Knob
In BottomTab, you should create a class in with a property minWidth: <your tab size>, and then use this class to style Tab component, like this:
const useStyles = makeStyles((theme) => ({
...
tabs: {
'& button': {
minWidth: 50
}
}
}));
const BottomTab = ({}) => {
const classes = useStyles()
return (
<Grid item direction="column" alignItems="center" justify="center">
<Tabs
value={0}
indicatorColor="primary"
textColor="primary"
variant="fullWidth"
className={classes.tabs}
>
<Tab label="Current" />
<Tab label="Set New" />
<Tab label="Alarm" />
</Tabs>
</Grid>
)
};
Have you tried adding component to its own grid and then changing the size.
Might not work, but worth a try.
Note: sorry for answering, but I can't comment yet due to reputation restriction.
Related
I have a two div I want to send selected text to another div using onSelect event? Right now entire para sending to another div but I want to send just selected text. How can I do this?
Demo:- https://codesandbox.io/s/selected-text-send-to-another-div-using-onselect-0ccnrn?file=/src/App.js
My Code:-
import React from "react";
import { Box, Grid, TextField, Typography } from "#material-ui/core";
import { useState } from "react";
const SendSelectedText = () => {
const [label1, setlabel1]=useState('');
const [para, setPara]=useState('This is Old Para');
const handleClick = () => {
setlabel1(para);
};
return (
<>
<Box className="sendSelectedTextPage">
<Grid container spacing={3}>
<Grid item xl={6} lg={6} md={6}>
<textarea onSelect={handleClick}>{para}</textarea>
</Grid>
<Grid item xl={6} lg={6} md={6}>
<TextField
variant="outlined"
size="small"
label="Label One"
value={label1}
multiline
rows={3}
className="sendSelectedTextPageInput"
/>
</Grid>
</Grid>
</Box>
</>
);
};
export default SendSelectedText;
Thanks for your support!
All you need is use window.getSelection().
Here is solution
import React from "react";
import { Box, Grid, TextField, Typography } from "#material-ui/core";
import { useState } from "react";
const SendSelectedText = () => {
const [label1, setlabel1] = useState("");
const [para, setPara] = useState("This is Old Para");
const handleMouseUp = () => {
setlabel1(window.getSelection().toString()); // setting up label1 value
};
return (
<>
<Box className="sendSelectedTextPage">
<Grid container spacing={3}>
<Grid item xl={6} lg={6} md={6}>
// changed event to onMouseUp
<textarea onMouseUp={handleMouseUp}>{para}</textarea>
</Grid>
<Grid item xl={6} lg={6} md={6}>
<TextField
variant="outlined"
size="small"
label="Label One"
value={label1}
multiline
rows={3}
className="sendSelectedTextPageInput"
/>
</Grid>
</Grid>
</Box>
</>
);
};
export default SendSelectedText;
Sandboxlink
You have to use the selection
const handleClick = (e) => {
setlabel1(
e.target.value.substring(e.target.selectionStart, e.target.selectionEnd)
);
};
or
const handleClick = (e) => {
setlabel1(
para.substring(e.target.selectionStart, e.target.selectionEnd)
);
};
Based on this
sandbox
I have the following react code and the thing that I want is to create a dashboard, but before I need to create a Grid for it.
I have the following code (using the material-ui grid system "https://material-ui.com/components/grid/")
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Grid from '#material-ui/core/Grid';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
paper: {
padding: theme.spacing(2),
textAlign: 'center',
color: theme.palette.text.secondary,
},
}));
function App() {
const classes = useStyles();
return (
<div>
<Grid container spacing={2}>
<Grid alignItems='baseline' item xs={3}>
<Paper className={`${classes.paper}`}>xs=3</Paper>
</Grid>
<Grid item xs={9}>
<Paper className={classes.paper}>xs=6</Paper>
<Paper className={`${classes.paper} ${styles.content}`} height="100%">xs=6</Paper>
</Grid>
</Grid>
</div>
);
}
export default App;
The result I want is the one from the 1 image, however the result that I have so far is the one from the second image, I am pretty sure that something is wrong with my code, I am not react expert.
Any help here will be aprecciated
I'm using React and material-ui.
My goal is to render a grid container, starting from an external javascript file, that exports its own array. This grid must have 3 items per row, but at the moment it just renders the items on a single column.
Here is the code:
import React from "react";
import CoffeeCard from "./CoffeeCard";
import { Grid } from "#material-ui/core";
import files from "./constants";
function Content() {
return (
<Grid direction="rows" container spacing={2}>
<Grid item xs={12} sm={4}>
{files.map((obj) => {
return (
<CoffeeCard
title={obj.title}
price={obj.price}
description={obj.description}
avatarUrl={obj.avatarUrl}
imgSrc={obj.imgSrc}
/>
);
})}
</Grid>
</Grid>
);
}
export default Content;
You need to move the nested Grid component for individual items inside the map function. Right now your code is only rendering 1 Grid item component with children , you need to render one for each row:
<Grid direction="rows" container spacing={2}>
{files.map((obj) => {
return (
<Grid item xs={12} sm={4}>
<CoffeeCard
title={obj.title}
price={obj.price}
description={obj.description}
avatarUrl={obj.avatarUrl}
imgSrc={obj.imgSrc}
/>
</Grid>
);
})}
</Grid>
</Grid>
The issue is how you are using the <Grid /> component from Material UI. Please refer to its documentation on Grid for more info.
Notably, you want your item to wrap each individual item. As you have it, you have a single item that wraps your content.
So just move your <Grid item> into your .map return value:
import React from 'react';
import CoffeeCard from './CoffeeCard';
import { Grid } from '#material-ui/core';
import files from './constants';
function Content() {
return (
<Grid direction="rows" container spacing={2}>
{files.map((obj) => {
return (
<Grid item xs={12} sm={4}>
<CoffeeCard
title={obj.title}
price={obj.price}
description={obj.description}
avatarUrl={obj.avatarUrl}
imgSrc={obj.imgSrc}
/>
</Grid>
);
})}
</Grid>
);
}
export default Content;
I am trying to build a nested horizontal tabs in MaterialUI, I mean, a first tabs level that, when you click on it, open a second tabs level.
Here is a link to the working replicable code example: https://codesandbox.io/s/sweet-pasteur-x4m8z?file=/src/App.js
The problem is: When I click on first level, second level is opened, when I click on a item from second level, I get this error
Material-UI: the value provided to the Tabs component is invalid.
None of the Tabs' children match with "value21".
You can provide one of the following values: value11
For replicate the error, you could do next steps:
Click in "Label 1"
Click in "Label 1.1"
Error is thrown
I do not understand why that error, if I am splitting values of each tab in different states and, supposedly, it is all Ok. Maybe the way I use for implementing the nested tab is wrong, any idea what could be happening?
Thank you.
I created three tab components, one parent and two children. Then I Imported the children tab components into the parent. You can use vertical tabs for the child tab components to help with the layout. check out the how the parent tab looks like. Note all these are tab components
// Parent tab component
import React from 'react';
import PropTypes from 'prop-types';
import SwipeableViews from 'react-swipeable-views';
import { makeStyles, useTheme } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import Typography from '#material-ui/core/Typography';
import Box from '#material-ui/core/Box';
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`full-width-tabpanel-${index}`}
aria-labelledby={`full-width-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `full-width-tab-${index}`,
'aria-controls': `full-width-tabpanel-${index}`,
};
}
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: theme.palette.background.paper,
width: 500,
},
}));
export default function FullWidthTabs() {
const classes = useStyles();
const theme = useTheme();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
const handleChangeIndex = (index) => {
setValue(index);
};
return (
<div className={classes.root}>
<AppBar position="static" color="default">
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
variant="fullWidth"
aria-label="full width tabs example"
>
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
</Tabs>
</AppBar>
<SwipeableViews
axis={theme.direction === 'rtl' ? 'x-reverse' : 'x'}
index={value}
onChangeIndex={handleChangeIndex}
>
<TabPanel value={value} index={0} dir={theme.direction}>
<ChildTabOne/>
</TabPanel>
<TabPanel value={value} index={1} dir={theme.direction}>
<ChildTabTwo/>
</TabPanel>
</SwipeableViews>
</div>
);
}
I am implementing auto-scroll option for my application. In below case channels are list of data which fetch from database. I used redux to call api. how can i connect InfiniteScroll and channels list to get auto-scroll feature?
import React, { Fragment } from "react";
import { Grid } from "#material-ui/core";
import ChannelCard from "./Card";
import CreateChannel from "./Create";
import SimpleSelect from "./Filter";
import InfiniteScroll from "react-infinite-scroll-component";
const ChannelList = ( {channels: { channels}}) => {
const [data, setData] = React.useState({
items: Array.from({ length: 20 })
});
const { items } = data;
const fetchMoreData = () => {
// a fake async api call like which sends
// 20 more records in 1.5 secs
setTimeout(() => {
setData({
items: items.concat(Array.from({ length: 20 }))
});
}, 1500);
};
//view
const view = (
<Fragment>
<Grid container>
<Grid item xs={6} sm={6} md={10} lg={10} xl={10}></Grid>
<Grid>
<SimpleSelect />
</Grid>
</Grid>
<Fragment>
<InfiniteScroll
dataLength={items.length}
next={fetchMoreData}
hasMore={true}
loader={<h4>Loading...</h4>}
>
<Grid container>
{channels.map(channel => (
<Grid key={channel._id} item xs={6} sm={6} md={3} lg={2} xl={2}>
<ChannelCard
channel={channel}
isAuthenticated={isAuthenticated}
/>
</Grid>
))}
</Grid>
</InfiniteScroll>
</Fragment>
</Fragment>
);
return <Fragment>{view}</Fragment>;
};
export default ChannelList;
(I used redux to call api. how can i connect InfiniteScroll and channels list to get auto-scroll feature?)
InfiniteScroll component requires the children to be the array of components that you want to have infinite scrolling on, since you have only one child which is the Grid component it is doing its job for only one item hence its not working: https://www.npmjs.com/package/react-infinite-scroll-component
just remove the wrapping Grid component
<InfiniteScroll
dataLength={items.length}
next={fetchMoreData}
hasMore={true}
loader={<h4>Loading...</h4>}
>
{channels.map(channel => (
<Grid key={channel._id} item xs={6} sm={6} md={3} lg={2} xl={2}>
<ChannelCard
channel={channel}
isAuthenticated={isAuthenticated}
/>
</Grid>
))}
</InfiniteScroll>