Component to call all material-ui Icon in React - reactjs

I want to implement a component which calls the corresponding icon from material-ui. I've made it work when manually calling it.
import MenuIcon from '#material-ui/icons/Menu';
export const Icon = (props) => {
return (
<div>
<MenuIcon/>
</div>
)
}
The problem is I don't know how to change the import for all icons.
I want to call this component the following way:
<Icon icon="MenuIcon" className="someClass" />
<Icon icon="LocationOn" className="someClass" />
<Icon icon="Notifications" className="OthersomeClass" />
I can't figure out how to import all icons and how to change my Icon component to work for any icon from the material-ui package.
Something like this...
import React from 'react';
import * as IconList from '#material-ui/icons/Menu'; //error
export const Icon = (props) => {
const {icon, className} = props;
return (
<`${icon}` className={className} /> {//error}
)
}
Any ideas?

You should be able to import all the icons using named imports or the star imports (* as).
Star imports should look like this
import * as Icons from "#material-ui/icons";
<Icon icon={Icons.Menu} className="someClass" />
<Icon icon={Icons.AccessAlarmIcon} className="someClass" />
Named imports should look like this
import { Menu, AccessAlarmIcon } from "#material-ui/icons";
<Icon icon={Menu} className="someClass" />
<Icon icon={AccessAlarmIcon} className="someClass" />
You can also refactor your Icon component to utilize the React children prop, that way you can better compose each icon on the Icon component.
So it should look something like this
import React from 'react';
export const Icon = ({ children }) => {
return (
<>{children}</>
)
}
Then you can use it like this
<Icon>
<Menu className="someClass" />
</Icon>
<Icon>
<AccessAlarmIcon className="someClass" />
</Icon>
PS:
Your star imports were from '#material-ui/icons/Menu' as opposed to just '#material-ui/icons' and that caused an error

Related

Unable to create custom tailwind component library

I try to create my own react component library based on tailwind CSS.
I start with a simple button component
import * as React from 'react'
interface Props {
text: string
onClick?(): any
}
export const Button = ({ text, onClick }: Props) => {
return (
<button onClick={onClick} className='bg-primary-500 rounded-md'>
{text}
</button>
)
}
I push it on npm : https://www.npmjs.com/package/tailwind-lib-quentin
Then I create a simple React app that use this package
import "tailwind-lib-quentin/dist/index.css";
import { Button } from "tailwind-lib-quentin";
function App() {
return (
<div className="App">
<Button text="Test" onClick={() => console.log("ok")} />
<div className="w-full h-40 bg-primary-500">Bonjour</div>
</div>
);
}
export default App;
as you can see I import the css of my package that extend tailwind but my components are not styled at all.
The button work but I can't see any style on it and I don't get any errors.
Here is reproductible example on Codesandbox : https://codesandbox.io/s/frosty-sea-1y879
here is the package repository : https://github.com/quentin-bardenet/tailwind-lib-quentin

Problem with showing a component which is in another file onclick

I am currently building an website in React with a navigation bar which I use Material-UI for.
My problem is that when I for example click "About" in my navigation bar, I want to show the content/component in About, and when I click Home I want the component Home to be shown and others hidden.
The problem is I am still a beginner in React and want to practice my React skills and now I have the navbar, Home, About in seperate files and not sure on how to pass through state, props and so in this case.
I will show a screen shot on the website and code-snippets to show my code so far.
My website:
File structure of my program:
Here is Code:
App.js:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import NavBar from './Components/Navigationbar'
import Home from './Components/Home'
import About from './Components/About'
class App extends Component {
constructor(props){
super(props);
this.state = {showAbout: true};
this.handleAbout = this.handleAbout.bind(this);
}
handleAbout(){
this.setState({showAbout: true})
}
render() {
return (
<div className="App">
<div className="App-header">
</div>
<NavBar></NavBar>
<p className="App-intro">
<Home></Home>
</p>
{this.state.showAbout ? <About /> : null}
</div>
);
}
}
export default App;
Home.jsx:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Typography from '#material-ui/core/Typography';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(3, 2),
backgroundColor: 'mistyrose'
},
}));
export default function PaperSheet() {
const classes = useStyles();
return (
<div>
<Paper className={classes.root}>
<Typography variant="h5" component="h3">
Home
</Typography>
<Typography component="p">
Welcome Home
</Typography>
</Paper>
</div>
);
}
About.jsx:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Typography from '#material-ui/core/Typography';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(3, 2),
backgroundColor: 'mistyrose'
},
}));
export default function PaperSheet() {
const classes = useStyles();
return (
<div>
<Paper className={classes.root}>
<Typography variant="h5" component="h3">
About
</Typography>
<Typography component="p">
About
</Typography>
</Paper>
</div>
);
}
And finally the navigation bar which is from Material UI:
Navigationbar.jsx:
import React from 'react';
import ReactDOM from 'react-dom';
import Button from '#material-ui/core/Button';
import App from '../App';
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 About from './About';
const useStyles = makeStyles({
root: {
flexGrow: 1,
},
});
function handleAbout(props){
alert('About');
}
const navBar = (props) => {
return (
<Paper >
<Tabs
//value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
centered
>
<Tab label="Home" />
<Tab label="About" onClick={() => handleAbout(props)} />
<Tab label="Contact" />
</Tabs>
</Paper>
);
}
//ReactDOM.render(<navBar />, document.querySelector('#app'));
export default navBar;
My problem is I want to when I click "About" in the navbar, I want to show the About component(the content in About.jsx) on my website but not sure on how to handle state and props in the case when they are in seperate files.
Would appreciate if someone could help me.
Thanks a lot.
You can use react-router for navigation. How to install and use it is quite nicely shown on the page: https://reacttraining.com/react-router/web/guides/quick-start
Oh boy, this is a big one...
In the simplest case, you pass state though props like this:
<ChildComponent showAbout={this.state.showAbout}/>, and access it in ChildComponent by props.showAbout (or this.props.showAbout if it's a class component).
But things can get complicated as your application scales. Values can only be passed through props downwards inside the component tree; in other words, a component can only see a state that's somewhere above it. You can't use state from a sibling component or a component below it.
And that's the whole reason state management libraries exist. They provide a 'global' state that is available anywhere in the app. Redux is one of them.
You should sit down and learn Redux, as you can't really make a big app without a state management tool.
Another thing you should learn is react-router, for client-side routing.
Those things combined will provide a powerful tool for making useful apps.

How to render text in component form <text /> in react?

I want to display text in the form of react component inside react app.
When I tried to render it, it gives me not defined error, which is understandable.
import React from 'react';
import HeaderClass from './Header.css';
import logo from '../../Assets/Images/logo.jpg'
const Header = () => {
return(
<div className="header-wrapper">
<p className="logo__tagline"> <text /> </p>
<img className="App__logo" src={logo} alt="Name" />
</div>
)
};
export default Header;
Not sure exactly what you are trying to do?
But if i understand correct you could do like this:
In the text file:
import React, { Fragment } from 'react'; // So it doesn't create a unnecessary node element. **Only available in react 16+
export const Text = () => <Fragment>Your text here</Fragment>;
and then you can bring in the text element and use it in your code:
import React from 'react';
import HeaderClass from './Header.css';
import logo from '../../Assets/Images/logo.jpg'
import { Text } from './Text'
const Header = () => {
return(
<div className="header-wrapper">
<p className="logo__tagline"> <Text /> </p>
<img className="App__logo" src={logo} alt="Name" />
</div>
)
};
export default Header;
Maybe i have misunderstood the question but i don't know why you would want to do this.

Material ui dropdown and other controls doesnt work propertly

I have an issue with the material-ui lib, where the dropdowns and menu doesnt work.
My code is the following.
import React from 'react';
import {Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle} from 'material-ui/Toolbar';
import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';
import injectTapEventPlugin from 'react-tap-event-plugin';
class Interruptions extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 1
};
injectTapEventPlugin();
}
handleChange(event, index, value) {
this.setState({value: value});
}
render(){
return (
<div className="interruptions__wrapper">
<Toolbar>
<ToolbarGroup firstChild={true}>
<DropDownMenu value={this.state.value} openImmediately={true} onChange={this.handleChange}>
<MenuItem value={1} primaryText="All Broadcasts" />
<MenuItem value={2} primaryText="All Voice" />
<MenuItem value={3} primaryText="All Text" />
<MenuItem value={4} primaryText="Complete Voice" />
<MenuItem value={5} primaryText="Complete Text" />
<MenuItem value={6} primaryText="Active Voice" />
<MenuItem value={7} primaryText="Active Text" />
</DropDownMenu>
</ToolbarGroup>
<ToolbarGroup>
<ToolbarTitle text="Options" />
</ToolbarGroup>
</Toolbar>
</div>
);
}
}
export default Interruptions;
And this is my main where i render the app in the html.
import React from 'react';
import ReactDOM from 'react-dom';
import Interruptions from '../components/Interruptions.jsx';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import {red500} from 'material-ui/styles/colors';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
const muiTheme = getMuiTheme({
palette: {
textColor: red500,
}
});
const InterruptionsApp = () => (
<MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}>
<Interruptions />
</MuiThemeProvider>
)
ReactDOM.render(<InterruptionsApp />, document.getElementById('myInterruptions'));
Im using openImmediately={true} to see if atleast the menu is showing up (and it does) but when i try to click on it to open it again it doesnt show.
Thanks in advice.
#Jeff McCloud is right. You should injectTapEventPlugin() before you are first use the render function from React-DOM.
I don't know how you build your application webpack or browserify?
I run in this issue too. Be sure that you have declared React, React-DOM, react-tap-event-plugin and all the React addons which you are using to the external libs. I am building a vendor.js for instance.
This approach prevents that you have multiple version of React in your project which could also produce this kind of behavior.

Material-ui svg-icons inside another element doesnt align to the center

I'm using the material ui library in my react project, and I have come across a strange issue, when I try to use svg icons inside a button-icon, the icom doesn't align to the center.
for example:
<ListItem key={product.id}
primaryText={product.title}
leftAvatar={<Avatar src={product.img}/>}
rightIcon={<IconButton><RemoveIcon/></IconButton>}/>
for this code I will get the following result:
And for this code:
<ListItem key={product.id}
primaryText={product.title}
leftAvatar={<Avatar src={product.img}/>}
rightIcon={<RemoveIcon/>}/>
I will get the following result :
My question is, how do i get to the result of my second example, but that the icon will we inside another element?
This is kind of late but I recently had the same issue and solved it by wrapping the IconButton component in a custom component and extending the css. You may have to change some other CSS to make it align perfectly but this worked for my use case.
import React, { PropTypes, Component } from 'react';
import IconButton from 'material-ui/IconButton';
const CustomIconButton = (props) => {
const { style } = props;
const additionalStyles = {
marginTop: '0'
};
return(
<IconButton {...props } style={{ ...style, ...additionalStyles }} iconStyle={{ fontSize: '20px' }}/>
);
};
CustomIconButton.PropTypes = {
// listed all the props that IconButton requires (check docs)
};
export default PPIconButton;
This is what a simplified usage of this custom IconButton looks like:
const deleteIconButton = (deleteFunc) => {
return <CustomIconButton
touch={true}
tooltip="Delete"
tooltipPosition="top-right"
onTouchTap={deleteFeed}
iconClassName="fa fa-trash"
/>;
};
class MyList extends Component {
render() {
return (
<div>
<List>
<ListItem value={ i } primaryText="My List Item" rightIcon={ deleteIconButton(() => this.props.deleteFeed(i) } />
) }
</List>
</div>
);
}
}
Passing the styles down to the inner element worked for me:
return <SvgIcon style={this.props.style} />
check this code, working fine for me
import React from 'react';
import List from 'material-ui/List';
import ListItem from 'material-ui/List/ListItem';
import Delete from 'material-ui/svg-icons/action/delete';
const MenuExampleIcons = () => (
<div>
<List style={{width:"300px"}}>
<ListItem primaryText="New Config" leftIcon={<Delete />} />
<ListItem primaryText="New Config" rightIcon={<Delete />} />
</List>
</div>
);
export default MenuExampleIcons;

Resources