I have created a customTheme file to extend the Chakra them and have created a custom component called card which I would like to have variants applicable, but for some reason the base styles show and the variants never work.
extendTheme.js
`
import { extendTheme } from '#chakra-ui/react';
import { ButtonStyles as Button } from './styles/components/ButtonStyles';
import { CardStyle as Card } from './styles/components/CardStyle';
const customTheme = extendTheme({
colors: {
brand: {
100: '#f7fafc',
900: '#f77070',
},
grey: {
100: '#eff3fa',
},
blue: {
100: '#0098ae',
},
red: {
100: '#ff3d3d',
200: '#f77070'
},
},
fonts: {
body: 'Graphik Font',
heading: 'Graphik Font',
},
fontWeights: {
hairline: 100,
thin: 200,
light: 300,
normal: 400,
medium: 500,
semibold: 600,
bold: 700,
extrabold: 800,
black: 900,
},
components: {
Button,
Card,
}
});
export default customTheme;
`
cardStyle.js
`
import { defineStyleConfig } from '#chakra-ui/react'
export const CardStyle = defineStyleConfig({
// The styles all Cards have in common
baseStyle: {
display: 'flex',
flexDirection: 'column',
background: 'white',
alignItems: 'center',
gap: 6,
},
// Two variants: rounded and smooth
variants: {
rounded: {
padding: 8,
borderRadius: 'xl',
boxShadow: 'xl',
},
smooth: {
padding: 6,
borderRadius: 'base',
boxShadow: 'md',
},
},
// The default variant value
defaultProps: {
variant: 'smooth',
},
})
`
Card.jsx
`
import { Box, useStyleConfig } from '#chakra-ui/react'
function CardTest(props) {
const { variant, ...rest } = props
const styles = useStyleConfig('Card', { variant })
// Pass the computed styles into the `__css` prop
return <Box __css={styles} {...rest} />
}
export default CardTest
`
including the card in another jsx
`
<CardTest variant='rounded'>
<Image
src={imageOne}
rounded='full'
w={32}
h={32}
boxShadow='md'
/>
<Heading mt={6} maxW={60} size='lg' textAlign='center' color='gray.700'>
Explore the outdoors
</Heading>
<Text mt={6} mb={6} size='sm' color='brand.900'>
some text in the card
</Text>
<Image src={imageOne} w={32} h={32} />
</CardTest>
`
import React from 'react';
import ReactDOM from "react-dom/client";
import { ChakraProvider } from '#chakra-ui/react';
import customTheme from './extendTheme';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<ChakraProvider theme={customTheme}>
<App />
</ChakraProvider>
</React.StrictMode>,
);
it uses the example off of the chakra docs but for some reason the variant never changes and I cannot see why when if i tell it o use Button as styles and not Card the variants work for button.
Aha! You're mapping CardStyles to Card, but actually rendering CardTest!
import { CardStyle } from './styles/components/CardStyle';
const customTheme = extendTheme({
// ...
components: {
Button,
Card: CardStyle, // targets Card component...
CardTest: CardStyle, // ...but you're rendering CardTest
}
});
Here's a working version, slightly simplified:
https://codesandbox.io/s/so-74816092-oio6qr?file=/src/index.js
Side note, CardStyle can't apply to Card, as it's a multipart component:
https://chakra-ui.com/docs/styled-system/component-style#single-part-and-multipart-components
https://chakra-ui.com/docs/styled-system/advanced-theming
https://chakra-ui.com/docs/components/card/theming
Outdated
You haven't included a snippet showing where you provide your custom theme to Chakra's ThemeProvider, so this may explain your issue:
// extendTheme.js
import { extendTheme } from "#chakra-ui/react"
const theme = extendTheme({
// ...
})
export default theme
import * as React from 'react'
import { ChakraProvider } from '#chakra-ui/react'
import theme from './extendTheme.js'
function App() {
// Wrap ChakraProvider at the root of your app
return (
<ChakraProvider theme={theme}>
<App />
</ChakraProvider>
)
}
// Now you can use these colors in your components
function Usage() {
return <Box bg="brand.100">Welcome</Box>
}
https://chakra-ui.com/docs/styled-system/customize-theme
Related
I'm making a tricky nav component using MUI Persistent Drawers with a React + Next structure. In order to get the content shrinking thanks to the state change, I had to put the whole navigation system inside of the _app.js file instead of having it in a distinct component.
Even though it clearly works, I wonder if it'll not impact rendering and performance once built. The makeStyles((theme) seems to work just fine but is not highlighted in VScode, probably because I used both of makeStyles, useTheme and ThemeProvider in the same file, as below :
import { makeStyles, useTheme } from '#material-ui/core/styles';
import { ThemeProvider } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({ ...
(className example:) appBarShift: {
width: `calc(100% - ${drawerWidth}px)`,
marginLeft: drawerWidth,
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
}, ... etc
Was it a good idea to put it all together in _app.js, or do I need to refactor everything into a new component passing props to parent somehow ?
Thanks for considering, best regards to all of you
I recommend you to put your theme inside a folder theme/theme.js and use createMuiTheme then in your app.js wrap your whole component with the theme provider ! That would spread your theme across the app and let you use it where you want ! Is the convention we got with material-ui.
theme/theme.js:
import { createMuiTheme } from "#material-ui/core/styles"
export const themeObject = {
palette: {
primary: { main: "#333333" },
secondary: { main: "#FD8C7C" },
},
backgroundColor: {
primary: { main: "#FEF8F8" },
secondary: { main: "#FFFFFF" },
},
breakpoints: {
values: {
xs: 0,
sm: 600,
md: 960,
lg: 1280,
xl: 1920,
},
},
overrides: {
MuiDivider: {
root: {
backgroundColor: "#FFFFFF",
},
},
},
}
export default createMuiTheme(themeObject)
pages/app,js:
import React from "react"
import { ThemeProvider } from "#material-ui/styles"
import Box from "#material-ui/core/Box"
import defaultTheme from "../theme/theme"
const App = () => {
return (
<Box>
<ThemeProvider theme={defaultTheme}>
...
</ThemeProvider>
</Box>
)
}
export default App
component/SideBar.js:
import React from "react"
import { makeStyles } from "#material-ui/core/styles"
const useStyles = makeStyles((theme) => ({
drawer: {
width: theme.sidebar.width,
color: theme.palette.primary
flexShrink: 0,
whiteSpace: "nowrap",
"& .MuiDrawer-paper": {
top: "unset",
},
},
drawerClose: {
transition: theme.transitions.create("width", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
overflowX: "hidden",
width: theme.spacing(7) + 1,
[theme.breakpoints.up("sm")]: {
width: theme.spacing(7) + 1,
},
},
expandButton: {
[theme.breakpoints.up("sm")]: {
marginLeft: theme.spacing(-2.5),
marginRight: theme.spacing(2.5),
},
},
}))
export default function Sidebar(props) {
const classes = UseStyles()
return (...)
}
In the SideBar you can see that i have use the theme.zindex.drawer who come from directly theme.js.
I also recommend you to go check this MUI THEMING that would let you dive into the theming more deeply !
I'm trying to create an AvatarGroup with MaterialUi, all my avatars obey a previously created style.
All, except the avatar automatically generated by AvatarGroup when the "max" parameter has been defined. :(
const styles = makeStyles((theme) => createStyles({
avatar: {
marginRight: theme.spacing(4),
borderWidth: '1px',
borderStyle: 'solid',
borderColor: grey[200],
width: theme.spacing(3),
height: theme.spacing(3)
}
}))
export default function GroupAvatars() {
const classes = styles();
const nameList = ['Alexandre', 'Regis', 'Leo', 'Thing', 'ola', 'que', 'tal']
const avatarList = nameList.map(name => {
return (<Avatar key={name}
className={classes.avatar}
alt={name}
/>)
})
return (
<AvatarGroup max={4} >
{avatarList}
</AvatarGroup>
);
}
it gives me this:
GroupAvatar with last avatar too big
as you can see the last avatar (+4) is way bigger than the others.
You can test the code on website like stackblitz.com using react:
stackblitz where you can test project
here are the import
import React from 'react';
import Avatar from '#material-ui/core/Avatar';
import { createMuiTheme } from '#material-ui/core/styles';
import { withStyles, WithStyles, createStyles, makeStyles, Theme } from '#material-ui/core/styles';
import { grey, blue } from '#material-ui/core/colors'
import AvatarGroup from '#material-ui/lab/AvatarGroup';
how do i make my avatar "+4" the same size as the other avatars ?
Target the avatar rule name for AvatarGroup instead of the individual Avatar components
<AvatarGroup max={4} classes={{avatar: classes.avatar}}>
I have 2 root components in react360.I have the main panel with information and my products and i have my 3d model.I want to communicate one another.Μore specifically I just want to click on the product then the color from my 3d model changes.At this time, my 3d model has value from the store I have originally defined, but while the price is changing, it is not renewed in the 3d model.for example when the application starts the original color of my model is blue but when I click on the first item it does not change to red. Wrere is the problem?????before
after
client.js
import { ReactInstance } from "react-360-web";
import { Location } from "react-360-web";
function init(bundle, parent, options = {}) {
const r360 = new ReactInstance(bundle, parent, {
// Add custom options here
fullScreen: true,
...options
});
// Render your app content to the default cylinder surface
r360.renderToSurface(
r360.createRoot("Center", {
/* initial props */
}),
r360.getDefaultSurface()
);
r360.renderToLocation(
r360.createRoot("React3DView"),
r360.getDefaultLocation()
);
// Load the initial environment
r360.compositor.setBackground(r360.getAssetURL("360_world.jpg"));
}
window.React360 = { init };
index.js
import { AppRegistry } from "react-360";
import Center from "./components/center";
import React3DView from "./components/obj";
AppRegistry.registerComponent("Center", () => Center);
AppRegistry.registerComponent("React3DView", () => React3DView);
reducer
initialState = {
data: [
{ id: 1, value: "MILEPTY.png" },
{ id: 2, value: "cleveland.png" },
{ id: 3, value: "phila.png" },
{ id: 4, value: "raptors.png" },
{ id: 5, value: "rockets.png" }
],
currentinfo: "Hello.Press click on T-shirt to show information",
currentcolor: "blue"
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case "INFO":
if (action.key === 1) {
return {
...state,
currentinfo: "Milwaukee bucks",
currentcolor: "red"
};
}
if (action.key === 2) {
return {
...state,
currentinfo: "Cleveland Cavaliers",
currentcolor: "green"
};
}
if (action.key === 3) {
return { ...state, currentinfo: "Philadelphia 76xers" };
}
if (action.key === 4) {
return { ...state, currentinfo: "Toronto Raptors" };
}
if (action.key === 5) {
return { ...state, currentinfo: "Huston Rockets" };
}
default:
return state;
}
};
export default reducer;
centerPanel
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import Products from "./products";
import { connect } from "react-redux";
class CenterPanel extends React.Component {
render() {
return (
<View style={styles.panel}>
<View style={{ flex: 1, flexDirection: "row" }}>
<View
style={{
width: 250,
height: 600
}}
>
<Text style={{ marginTop: "100" }}>{this.props.currentinfo}</Text>
</View>
<View
style={{
width: 1000,
height: 600,
backgroundColor: "green"
}}
>
<View style={{ flex: 1, flexDirection: "row" }}>
{this.props.data.map(element => (
<Products
key={element.id}
value={element.value}
id={element.id}
/>
))}
</View>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
panel: {
// Fill the entire surface
width: 1000,
height: 600,
backgroundColor: "rgba(255, 255, 255, 0.4)"
}
});
const mapStateToProps = state => {
return {
data: state.data,
currentinfo: state.currentinfo
};
};
export default connect(mapStateToProps)(CenterPanel);
products
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import { connect } from "react-redux";
class Products extends React.Component {
state = {
img: this.props.value
};
render() {
return (
<View
style={styles.panelimages}
onInput={() => this.props.onText(this.props.id)}
>
<Image style={styles.images} source={asset(this.state.img)} />
</View>
);
}
}
const styles = StyleSheet.create({
panelimages: {
width: 150,
height: 150,
marginTop: 200,
backgroundColor: "white"
},
images: {
width: 150,
height: 150
}
});
const mapDispatchToProps = dispatch => {
return {
onText: id => dispatch({ type: "INFO", key: id })
};
};
export default connect(
null,
mapDispatchToProps
)(Products);
center
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import { createStore } from "redux";
import { Provider } from "react-redux";
import reducer from "../store/reducer";
import CenterPanel from "./centerPanel";
// const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
const store = createStore(reducer);
export default class Center extends React.Component {
render() {
return (
<Provider store={store}>
<CenterPanel />
</Provider>
);
}
}
objpanel
import React from "react";
import {
asset,
AppRegistry,
StyleSheet,
Text,
View,
VrButton,
Image
} from "react-360";
import Entity from "Entity";
import { connect } from "react-redux";
class Object3d extends React.Component {
render() {
return (
<View>
<Entity
source={{ obj: asset("t-shirt.obj") }}
style={{
transform: [{ translate: [-3.5, -3.5, -2.8] }],
color: this.props.currentcolor -------->here is problem
}}
/>
</View>
);
}
}
const mapStateToProps = state => {
return {
currentcolor: state.currentcolor
};
};
export default connect(mapStateToProps)(Object3d);
obj
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import { createStore } from "redux";
import { Provider } from "react-redux";
import reducer from "../store/reducer";
import Object3d from "./objpanel";
// const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
const store = createStore(reducer);
export default class React3DView extends React.Component {
render() {
return (
<Provider store={store}>
<Object3d />
</Provider>
);
}
}
I've tried to do this with redux but in the end I had more problems implementing it than it was worth. In order to implement something like that you would need to follow the code that is described here:
React 360 multi panel example
Additionally, I've implemented what you are trying to do without redux. You can look at the code in this repository and also view the production link here. Its modeled after the react 360 code.
CryptoDashboardVR repo
CryptodashboardVR Multipanel synchronization
Finally, If you still need help, check out my course on React 360. I explain the concepts used. Udemy react 360.
Hope that helps. For now, I would abandon the redux approach until maybe 2.0 comes out.
I am new to react-native framework and learning how to use navigator. I tried to implement jump between two pages of APP. From "Boy" to "Girl" then back to "Boy".
Here is the code in APP.js:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, {Component, } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Image,
} from 'react-native';
import Boy from './Boy';
import {Navigator} from 'react-native-deprecated-custom-components';
import TabNavigator from 'react-native-tab-navigator';
export default class imooc_gp extends Component {
constructor(props){
super(props);
this.state = {
selectedTab:'tb_popular',
}
}
render() {
return (
<View style={styles.container}>
<Navigator
initialRoute = {{
title:'example',
component: Boy
}}
renderScene = {(route, navigator) =>{
let Component = route.component;
return <Component navigator = {navigator} {...route.params}/>
}}
></Navigator>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
page1 :{
flex: 1,
backgroundColor: 'red',
},
page2: {
flex: 1,
backgroundColor: 'yellow',
},
image: {
height: 22,
width: 22,
}
});
Boy.js:
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet
}from 'react-native';
import Girl from './Girl';
export default class Boy extends Component{
constructor(props){
super(props);
this.state = {
word: ''
}
}
render(){
return (
<View style = {styles.container}>
<Text style = {styles.text}> I am a boy</Text>
<Text style = {styles.text}
onPress = {()=>{
this.props.navigator.push({
title:'Girl',
component: Girl,
params:{
word: 'A Rose',
onCallBack: (word)=>{
this.setState({
word: word
})
}
}
})
}}>Send girl a Rose</Text>
<Text style = {styles.text}>{this.state.word}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'gray',
justifyContent: 'center'
},
text: {
fontSize: 20,
}
})
Girl.js:
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet
}from 'react-native';
export default class Girl extends Component{
constructor(props){
super(props);
this.state = {
}
}
render(){
return(
<View styles = {styles.container}>
<Text style = {styles.text}> I am a Girl</Text>
<Text style = {styles.text}>{this.state.word}</Text>
<Text style = {styles.text}
onPress = {()=>{
this.props.onCallBack('A box of chocolate')
this.props.navigator.pop()
}}>return chocolate</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'red',
justifyContent: 'center',
},
text: {
fontSize: 22
}
})
And I received the error message on iPhone emulator showed in the image:
I guess the error could be caused by wrong usage grammar of Navigator in different react-native version.
In my experience, I have found it more useful to use react-navigation library. This allows one to create a router files that lists all the pages that you want your app to navigate around; in your case, it could be Boy.js and Girl.js. Example given below:
import React from 'react';
import { StackNavigator } from 'react-navigation';
import { Boy, Girl } from '../app';
export const Screens = StackNavigator({
Boy: {
screen: Boy,
},
Girl: {
screen: Girl
}
});
And once you render the Screen component, Boy.js and Girl.js will each have access to the other screen via the "navigation.navigate" props.
So in your Boy component, rather than:
onPress = {()=>{
this.props.navigator.push({
title:'Girl',
component: Girl,
params:{
word: 'A Rose',
onCallBack: (word)=>{
this.setState({
word: word
})
}
}
})
You could simply write:
this.props.navigation.navigate("Girl")
All you would need to do is import the Girl component.
Hope this helps!
I'm trying to achieve dark and light themes in my React app. I know how themes work, so I'm configuring my button like below, for example :
const Button = styled.button`
/* some styles */
color: ${props => props.theme.main}
`;
Then I'm defining themes as consts:
const dark = {
main: 'black',
text: 'switch to light mode'
};
const light = {
main: 'white',
text: 'switch to dark mode'
};
And when I want to use the theme somewhere I do it like this:
<ThemeProvider theme={dark}>
<Button>{dark.text}</Button>
</ThemeProvider>
But what I want to achieve is to change the theme dynamically (on a click function on the button probably). I'm kind of new to React so please don't be mean to me.
Something like this? Demo
import React, { Component } from 'react';
import { render } from 'react-dom';
import styled, { ThemeProvider } from 'styled-components';
const themes = {
'light': {
main: '#EFEFEF',
},
'dark': {
main: '#666',
}
}
const DynamicDiv = styled.div`
background: ${({ theme }) => theme.main};
`
class App extends Component {
constructor() {
super();
this.state = {
name: 'React',
theme: themes['light']
};
}
handleDark = () => {
this.setState({ theme: themes['dark'] })
}
render() {
return (
<ThemeProvider theme={this.state.theme}>
<div>
<DynamicDiv>{this.state.name}</DynamicDiv>
<div onClick={this.handleDark}>Change to Dark</div>
</div>
</ThemeProvider>
);
}
}
render(<App />, document.getElementById('root'));