Why is it impossible to style a success button in #material-ui - javascript

I am using https://material-ui.com/
My objective is to get a success Button, and Chip. Does anyone know how to do this without these hacky solutions: Material-ui #next customize button colors?
The goal isn't to create a styled component, the goal is to be able to use <Button color="success" /> or <Chip color="success" />.
I have tried <Box bgcolor="success.main">{ props => <Chip {...props} />}</Box> to no avail. I would be OK with using Box but not even that works.
It seems a bit ridiculous that these basic UI things are so cumbersome with this library. Success and Error colors should be a default, and they seem to be missing from every single component in this library. Am I missing something?

This is not a full/working example, but hopefully it provides some context. The Main component is included (eventually) via an AuthenticatedRoute within the Router shown in App.js. It doesn't really add anything to show all that complexity, but I wanted to give you some context.
Steps:
Create theme using createMuiTheme.
Add a ThemeProvider component with a theme prop that accepts your theme. This should be a parent to any Component that will make use of the theme, ours is in App.js.
Use the optional argument that makeStyles has to pass your theme into your Component (Main in my example). You can see examples where we access theme properties such as theme.palette.brand.primary.
Use the useStyles hook to create a variable in your component.
Apply those styles to your Component's elements via the className prop. For example, <div className={classes.root}>...</div>
Repeat 3-5 on any Component that needs styling.
I'm still learning my way around Material UI; we just recently migrated from react bootstrap to MUI. We still have some *.scss files laying around, but everything can co-exist. Our eventual plan is to move everything into the makeStyles hooks, but we haven't had time to refactor everything yet.
As a non-CSS guru, I much prefer to write the styling as code (even if I have to write some boilerplate) than to deal with .scss files and specificity/inheritance.
Theme.js:
import { createMuiTheme } from '#material-ui/core/styles';
export default createMuiTheme({
palette: {
brand: {
primary: '#1b3c6b',
primaryLight: '#adceff',
secondary: '#2a5da6',
tertiary: '#bf1e2e',
tertiaryLight: '#c35f69',
},
},
typography: {
color: '#333',
},
sidebar: {
header: {
background: '#2a5da6',
},
content: { background: '#fff' },
},
status: {
danger: 'orange',
},
});
Main.js (partial):
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
},
appBar: {
background: theme.palette.brand.primary,
boxShadow: 'none',
'& .MuiTabs-indicator': {
backgroundColor: theme.palette.brand.primaryLight,
height: 3,
},
position: 'fixed',
zIndex: 1000,
},
}));
const Main = React.memo(props => {
const classes = useStyles();
...
return (
<div className={classes.root}>
<AppBar className={classes.appBar} position="static">
....
</AppBar>
</div>
);
}
App.js (partial):
import { CssBaseline, ThemeProvider } from '#material-ui/core';
import theme from 'Theme/Theme'; // Theme.js from above
...
class App extends Component {
...
render() {
...
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Router>
...
</Router>
</ThemeProvider>
);
}
...
}

Related

FreshDesk widget not switching between the freshDeskAdmin and the freshDesk API in Next.js

I am trying to load a FreshDesk widget in a Next.js app, but the widget is not switching between the freshDeskAdmin and the freshDesk API when I pass a prop to the component.
I have imported the useConfig hook, which contains my env variables and I am using a ternary operator to determine which widget ID to use. Still, the widget is always showing me the wrong one.
The issue seems to disappear when I do refresh the page.
I have tried moving the ternary operator inside the fwSettings object, but it still doesn't work. I am unsure what the problem is, could you help me to fix this?
An example plus the code below
I cannot show more due policies but what I did was refresh the page and the right widget loaded back. I have a widget called 'help' and one 'support'.
Depending on the page, it shows one or the other. In this image should show support
The FreshDesk component
import { useConfig } from '#lib/config';
import Script from 'next/script';
const FreshDesk = ({ isStudyAdmin }) => {
const { freshDesk, freshDeskAdmin } = useConfig();
return (
<>
<Script
src={`https://widget.freshworks.com/widgets/${
isStudyAdmin ? freshDeskAdmin : freshDesk
}.js`}
strategy="afterInteractive"
/>
<Script id="freshdesk-initialization" strategy="afterInteractive">
{`window.fwSettings={
'widget_id': ${isStudyAdmin ? freshDeskAdmin : freshDesk}
};
!function(){if("function"!=typeof window.FreshworksWidget)
{var n=function(){n.q.push(arguments)};
n.q=[],window.FreshworksWidget=n}}()`}
</Script>
</>
);
};
export default FreshDesk;
And how it is used and you can find it in the bottom of the script I removed what was not necessary in this code
import { useCheckAccess } from '#lib/authentication';
import { AppBar, Box, Tab, Tabs, Toolbar } from '#mui/material';
import { useRouter } from 'next/router';
import { useIntl } from 'react-intl';
import FreshDesk from 'src/components/FreshDesk';
import Link from 'src/components/LinkNext';
import AdminLayout from 'src/layouts/AdminLayout';
function AdminSettingsLayout({ children }) {
const intl = useIntl();
const router = useRouter();
const { checkAccess } = useCheckAccess();
return (
<AdminLayout>
<Box
sx={{
bgColor: 'white',
border: '1px solid lightgrey',
borderRadius: 2,
}}
>
<AppBar
position="static"
color="transparent"
square
elevation={0}
sx={{ boxShadow: '0px -1px 0px lightgrey inset' }}
>
........
........
</AppBar>
<FreshDesk isStudyAdmin="true" />
{children}
</Box>
</AdminLayout>
);
}
export default AdminSettingsLayout;

How do I create a reusable component in react native? with this example

I managed to render the component for myself after so long trying, sorry I am new to react native, but I want to use the <DarkLight> component to cover everything inside and style the whole application and be able to continue using everything, as an example : when we use a <view>: we put in the middle another functional component like <Text> or another <View> you can use everything inside it and in turn its properties, I want to use <DarkLight> in the same way as if it were a <View > that encompasses the entire app Modifying the styles or properties and placing more components inside it, such as placing a <table> inside <DarkLight> (the table is also a component created to reuse) to be able to give it properties or styles also separately or if I create another component like the example of the <Table> put it inside <DarkLight> and keep it working .... in <DarkLight> I put a <Text> and it does nothing, this is what I mean ..., and I keep using all with props, I took this example from expo co lor-schemes, I would like to make it a reusable component that encompasses my entire application so that I am able to reuse it in another application. I want to learn how to build reusable components. I see props and components I do not want to advance without understanding well, being able to create a component that I can reuse. But I'm not sure if in these cases I should use state .. someone can help me and explain and I apologize for the inconvenience. :>
// App.js
import React from 'react';
import Home from './src/Home'
export default function App() {
return (
<Home/>
);
}
// Home.js
import React from 'react';
import { Text, StyleSheet, View, useColorScheme, Button } from 'react-native';
import DarkLight from '../src/Components/Dark_Light.js'
export default function Home() {
return (
<DarkLight>
<Text>Hello World</Text>
</DarkLight>
);
}
// Dark_Light.js
import React from 'react';
import { Text, StyleSheet, View, useColorScheme } from 'react-native';
import {globalStyles} from '../Styles/globalStyles'
const ThemeDark = (props) => {
const colorScheme = useColorScheme();
const themeTextStyle = colorScheme === 'light' ? globalStyles.lightThemeText : globalStyles.darkThemeText;
const themeContainerStyle = colorScheme === 'light' ? globalStyles.lightContainer : globalStyles.darkContainer;
const {children} = props;
return(
<View style={[globalStyles.container, themeContainerStyle]}>
<Text style={[globalStyles.text, themeTextStyle]}>
Color scheme: {colorScheme}
{children}
</Text>
{children}
</View>
)
}
export default function DarkLight() {
return (
<ThemeDark>
</ThemeDark>
);
}
// globalStyles.js // the global styles would like to be able to pass properties to it and modify it, what am I doing wrong? and what should i do?
import { StyleSheet } from "react-native";
export const globalStyles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
lightContainer: {
backgroundColor: '#d0d0c0',
},
darkContainer: {
backgroundColor: '#242c40',
},
lightThemeText: {
color: '#242c40',
},
darkThemeText: {
color: '#d0d0c0',
},
});

Apply a different theme on a per story basis storybook

I am making a library of react components in storybook (v6.1.14)
I have two different themes, basically and light and dark version.
I wrap all of my stories in the <ThemeProvider> like this:
import React from "react"
import {dark} from "../src/Themes/Theme";
import { ThemeProvider } from "styled-components";
import { GlobalStyles } from "../src/lib/Themes";
// apply our projects theme to our stories
const ThemeDecorator = storyFn => (
<ThemeProvider theme={dark}>
<GlobalStyles />
{storyFn()}
</ThemeProvider>
)
export default ThemeDecorator;
This is applied through the preview.js file like so:
const { addDecorator } = require("#storybook/react");
import ThemeDecorator from "./themeDecorator"
// Add our project theme, add a global stylesheet
addDecorator(ThemeDecorator);
So now everything has the dark theme applied, however, for each component I want to show two stories: One for the light theme and one for the dark theme - how do I make a story take on a different theme to the one globally declared?
I had the same problem as well. From the Storybook docs, I found this answer.
So basically, you can use decorators with your template and apply styling to it.
const Template: Story<LogoProps> = (args) => {
const { version } = args;
return <Logo {...args} version={version} />;
};
export const Light = Template.bind({});
Light.args = {
version: 'light',
};
Light.decorators = [
(LightLogo) => (
<div style={{ backgroundColor: 'black', padding: '5px 7px' }}>
<LightLogo />
</div>
),
];

infinite Render in React

I am having problem figuring out why my application is doing endless render.
Inside, My stateful component, I am calling a redux action in componentDidMount method (calling componentWillMount also do endless render)
class cryptoTicker extends PureComponent {
componentDidMount() {
this.props.fetchCoin()
// This fetches some 1600 crypto coins data,Redux action link for the same in end
}
render() {
return (
<ScrollView>
<Header />
<View>
<FlatList
data={this.state.searchCoin ? this.displaySearchCrypto : this.props.cryptoLoaded}
style={{ flex: 1 }}
extraData={[this.displaySearchCrypto, this.props.cryptoLoaded]}
keyExtractor={item => item.short}
initialNumToRender={50}
windowSize={21}
removeClippedSubviews={true}
renderItem={({ item, index }) => (
<CoinCard
key={item["short"]}
/>
)}
/>
</View>
</ScrollView>
)
}
}
In CoinCard I am literally doing nothing besides this (Notice CoinCard inside Flat list)
class CoinCard extends Component {
render () {
console.log("Inside rende here")
return (
<View> <Text> Text </Text> </View>
)
}
}
Now, When I console log in my coincard render, I can see infinite log of Inside rende here
[Question:] Can anyone please help me figure out why this could be happening?
You can click here to see my actions and click here to see my reducer.
[Update:] My repository is here if you want to clone and see it by yourself.
[Update: 2]: I have pushed the above shared code on github and it will still log endless console.log statements (if you can clone, run and move back to this commit ).
[Update:3]: I am no longer using <ScrollView /> in <FlatList /> also when I mean endless render, I mean is that it is endless (& Unecessarily) passing same props to child component (<Coincard />), if I use PureComponent, it won't log endlessly in render () { but in componentWillRecieveProps, If I do console.log(nextProps), I can see the same log passed over and over again
There are some points to note in your code.
The CoinCard Component must be a PureComponent, which will not re-render if the props are shallow-equal.
You should not render your Flatlist inside the ScrollView component, which would make the component render all components inside it at once which may cause more looping between the Flatlist and ScrollView.
You can also a definite height to the rendered component to reduce the number of times component is rendered for other props.
Another thing to note is, only props in the component are rendered on scroll bottom, based on the log statement mentioned below.
import {Dimensions} from 'react-native'
const {width, height} = Dimensions.get('window)
class CoinCard extends React.PureComponent {
render () {
console.log(this.props.item.long) //... Check the prop changes here, pass the item prop in parent Flatlist. This logs component prop changes which will show that same items are not being re-rendered but new items are being called.
return (
<View style={{height / 10, width}}> //... Render 10 items on the screen
<Text>
Text
</Text>
</View>
)
}
}
UPDATE
This extra logging is due to the props being from the Flatlist to your component without PureComponent shallow comparison.
Note that componentWillReceiveProps() is deprecated and you should avoid them in your code.
React.PureComponent works under the hood and uses shouldComponentUpdate to use shallow comparison between the current and updated props. Therefore log console.log(this.props.item.long) in your PureComponent' render will log the unique list which can be checked.
Like izb mentions, the root cause of the pb is the business call that is done on a pure component whereas it is just loaded. It is because your component make a business decision (<=>"I decide when something must be showed in myself"). It is not a good practice in React, even less when you use redux. The component must be as stupid a possible and not even decide what to do and when to do it.
As I see in your project, you don't deal correctly with component and container concept. You should not have any logic in your container, as it should simply be a wrapper of a stupid pure component. Like this:
import { connect, Dispatch } from "react-redux";
import { push, RouterAction, RouterState } from "react-router-redux";
import ApplicationBarComponent from "../components/ApplicationBar";
export function mapStateToProps({ routing }: { routing: RouterState }) {
return routing;
}
export function mapDispatchToProps(dispatch: Dispatch<RouterAction>) {
return {
navigate: (payload: string) => dispatch(push(payload)),
};
}
const tmp = connect(mapStateToProps, mapDispatchToProps);
export default tmp(ApplicationBarComponent);
and the matching component:
import AppBar from '#material-ui/core/AppBar';
import IconButton from '#material-ui/core/IconButton';
import Menu from '#material-ui/core/Menu';
import MenuItem from '#material-ui/core/MenuItem';
import { StyleRules, Theme, withStyles, WithStyles } from '#material-ui/core/styles';
import Tab from '#material-ui/core/Tab';
import Tabs from '#material-ui/core/Tabs';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import AccountCircle from '#material-ui/icons/AccountCircle';
import MenuIcon from '#material-ui/icons/Menu';
import autobind from "autobind-decorator";
import * as React from "react";
import { push, RouterState } from "react-router-redux";
const styles = (theme: Theme): StyleRules => ({
flex: {
flex: 1
},
menuButton: {
marginLeft: -12,
marginRight: 20,
},
root: {
backgroundColor: theme.palette.background.paper,
flexGrow: 1
},
});
export interface IProps extends RouterState, WithStyles {
navigate: typeof push;
}
#autobind
class ApplicationBar extends React.PureComponent<IProps, { anchorEl: HTMLInputElement | undefined }> {
constructor(props: any) {
super(props);
this.state = { anchorEl: undefined };
}
public render() {
const auth = true;
const { classes } = this.props;
const menuOpened = !!this.state.anchorEl;
return (
<div className={classes.root}>
<AppBar position="fixed" color="primary">
<Toolbar>
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
<MenuIcon />
</IconButton>
<Typography variant="title" color="inherit" className={classes.flex}>
Title
</Typography>
<Tabs value={this.getPathName()} onChange={this.handleNavigate} >
{/* <Tabs value="/"> */}
<Tab label="Counter 1" value="/counter1" />
<Tab label="Counter 2" value="/counter2" />
<Tab label="Register" value="/register" />
<Tab label="Forecast" value="/forecast" />
</Tabs>
{auth && (
<div>
<IconButton
aria-owns={menuOpened ? 'menu-appbar' : undefined}
aria-haspopup="true"
onClick={this.handleMenu}
color="inherit"
>
<AccountCircle />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={this.state.anchorEl}
anchorOrigin={{
horizontal: 'right',
vertical: 'top',
}}
transformOrigin={{
horizontal: 'right',
vertical: 'top',
}}
open={menuOpened}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>Profile</MenuItem>
<MenuItem onClick={this.handleClose}>My account</MenuItem>
</Menu>
</div>
)}
</Toolbar>
</AppBar>
</div >
);
}
private getPathName(): string {
if (!this.props.location) {
return "/counter1";
}
return (this.props.location as { pathname: string }).pathname;
}
private handleNavigate(event: React.ChangeEvent<{}>, value: any) {
this.props.navigate(value as string);
}
private handleMenu(event: React.MouseEvent<HTMLInputElement>) {
this.setState({ anchorEl: event.currentTarget });
}
private handleClose() {
this.setState({ anchorEl: undefined });
}
}
export default withStyles(styles)(ApplicationBar);
Then you will tell me: "but where do I initiate the call that will fill my list?"
Well I see here that you use redux-thunk (I prefer redux observable... more complicated to learn but waaaaaaaaaaaaaaaaay more powerful), then this should be thunk that initiates the dispatch of this!
To summarize:
Components: the stupidest element that normally should have only the render method, and some other method handler to bubble up user events. This method only takes care of showing its properties to the user. Don't use the state unless you have a visual information that belongs only to this component (like the visibility of a popup for example). Anything that is showed or updated comes from above: a higher level component, or a container. It doesn't decide to update its own values. At best, it handles a user event on a subcomponent, then bubble up another event above, and... well maybe at some point, some new properties will be given back by its container!
Container: very stupid logic that consists in wrapping a top level component into redux for it to plug events to actions, and to plug some part of the store to properties
Redux thunk (or redux observable): it is the one that handles the whole user application logic. This guy is the only one who knows what to trigger and when. If a part of your front end must contain the complexity, it's this one!
Reducers: define how to organize the data in the store for it to be as easily usable as possible.
The store: ideally one per top level container, the only one that contains the data that must be showed to the user. Nobody else should.
If you follow these principles, you should never face any issue like "why the hell this is called twice? and... who made it? and why at this moment?"
Something else: if you use redux, use an immutability framework. Otherwise you may face issues as reducers must be pure functions. For this you can use a popular one immutable.js but not convenient at all. And the late ousider that is actually a killer: immer (made by the author or mobx).
It seems Jacob in the above comment has managed to make the component render only twice.
This will definitely cause double initial render (and would cause an infinite render if it wasn't a PureComponent):
componentDidUpdate() {
var updateCoinData;
if (!updateCoinData) { // <- this is always true
updateCoinData = [...this.props.cryptoLoaded];
this.setState({updateCoinData: true}); // <- this will trigger a re render since `this.state.updateCoinData` is not initially true
}
...
}
Link to the issue in your repository

Is there a way to theme with emotion without "styled"

With emotion (https://github.com/emotion-js/emotion) I know I can theme with css and styled together with something like:
const carouselCss = ({ theme }) => css`
.. css properties etc
`;
const CarouselDiv = styled('div')`
${carouselCss};
`;
Then in JSX:
<ThemeProvider theme={{ stuff: 'blah' }}>
<CarouselDiv>
..
</CarouselDiv>
</ThemeProvider>
But is there any elegant way to theme with only css - prefer not to use componentized styles because I want to keep to semantic html elements in JSX (also have a massive code base and its easier to migrate from sass to emotion without having to use styled)
I know I can do something like:
const carouselCss = (theme) => css`
.. css properties etc
`;
then jsx:
<div className={carouselCss(this.props.theme)}>
..
</div>
But it means passing a theme prop all the time from the component - which is a little cumbersome
Is there a better way to do this ? Somehow wrap css with something so it has theme vars injected ?
ThemeProvider will get you that. Here is an example with both styled and css options shown :
/** #jsx jsx */
import { jsx } from '#emotion/core'
import styled from '#emotion/styled'
import { ThemeProvider } from 'emotion-theming'
const theme = {
colors: {
primary: 'hotpink'
}
}
const SomeText = styled.div`
color: ${props => props.theme.colors.primary};
`
render(
<ThemeProvider theme={theme}>
<SomeText>some text</SomeText>
<div css={theme => ({ color: theme.colors.primary })}>
some other text
</div>
</ThemeProvider>
)
You could use theme HoC. But if your concern is prop passing to slider, this HoC is basically doing the same, i.e. injects theme into this.props.theme.
Personally, i would use ThemeProvider API if possible, maybe with function-style theme, as pointed out in the docs:
// function-style theme; note that if multiple <ThemeProvider> are used,
// the parent theme will be passed as a function argument
const adjustedTheme = ancestorTheme => ({ ...ancestorTheme, color: 'blue' });

Categories

Resources