Fluent UI React - how to apply global component styles with Fluent ThemeProvider - fluent-ui

I'm working with the theming code below. I'm able to apply a global Fluent theme with the ThemeProvider and createTheme utility, but when I add component specific themes, I'm not getting any typings, which makes theming very difficult.
So my question is: how do I apply global component-specific styles using Fluent ThemeProvider with strong typing.
If, for example, I wanted to add a box shadow to all Fluent PrimaryButtons, I wouldn't know what properties to access on the components key passed into createTheme.
If you've done any global component theming, please let me know what pattern you used and if I'm on the right track, thanks!
import { createTheme } from '#fluentui/react';
import { PartialTheme } from '#fluentui/react-theme-provider';
// Trying to add global component styles (not getting typings)
const customComponentStyles = {
PrimaryButton: {
styles: {
root: {
background: 'red'
}
}
}
};
export const fluentLightTheme: PartialTheme = createTheme({
components: customComponentStyles, // Want to apply component styles
palette: {
themePrimary: '#0078d4',
themeLighterAlt: '#eff6fc',
themeLighter: '#deecf9',
themeLight: '#c7e0f4',
themeTertiary: '#71afe5',
themeSecondary: '#2b88d8',
themeDarkAlt: '#106ebe',
themeDark: '#005a9e',
themeDarker: '#004578',
neutralLighterAlt: '#faf9f8',
neutralLighter: '#f3f2f1',
neutralLight: '#edebe9',
neutralQuaternaryAlt: '#e1dfdd',
neutralQuaternary: '#d0d0d0',
neutralTertiaryAlt: '#c8c6c4',
neutralTertiary: '#a19f9d',
neutralSecondary: '#605e5c',
neutralPrimaryAlt: '#3b3a39',
neutralPrimary: '#323130',
neutralDark: '#201f1e',
black: '#000000',
white: '#ffffff'
}
});

The problem here is, that components is just a Record<string, ComponentStyles>, where ComponentStyles then just is a quite unspecific object of the form { styles?: IStyleFunctionOrObject<any, any>}. They would have to add an entry for every possible I<Component>Styles interface to ComponentsStyles, which I guess would be too much work and errorprone (e.g. forgetting to add a new component here ...).
Since all the I<Component>Styles interfaces are exported by Fluent, I always define the styles for each component separately and than merge them in the components object:
const buttonStyles: IButtonStyles = {
root: {
backgroundColor: 'red'
}
};
export const fluentLightTheme: PartialTheme = createTheme({
components: { PrimaryButton: { styles: buttonStyles } },
});
Here is a codepen example I created by using one of Fluent UIs basic Button examples: https://codepen.io/alex3683/pen/WNjmdWo

Related

React Native - What's the best way to provide a global theme?

I've started using RN recently and have been doing some research on the implementation of themes and/or a dark-light mode. Here's roughly how I understand the two main options so far:
Context: Easy setup and can be accessed via hook inside the component that needs it. I count things like the React Navigation themes since that works, in essence, the same way(?)
Styled Components: Essentially just replacing the components with custom ones that access the current theme and that can then be set up to change their props on toggle if needed.
What I don't like about context, is that (the way I understand it) it wouldn't let me access the theme when using a StyleSheet, since that's outside the component. With the styled components on the other hands I'm not sure if I can cover all options inside my custom components, wouldn't I still need some sort of hook in each component anyway?
I was also thinking about just saving the current theme into my Store (in my case Zustand), together with an action that lets me toggle to a dark-mode. But so far, I haven't really seen anyone else do that, is there a downside to doing it that way?
It's not hard to pass context to your stylesheet, it just requires a bit of extra boilerplate. Something like the below:
import ThemeContext from '<path>';
export default () => {
const theme = useContext(ThemeContext);
const stylesWithTheme = styles(theme);
return <Text style={stylesWithTheme.text>Hi</Text>;
}
const styles = theme => StyleSheet.create({
text: {
color: themeStyles.color[theme];
}
});
const themeStyles = {
color: {
dark: '#FFF',
light: '#000',
},
};
I don't think using styled components would be a big departure from the above scheme.
If you did store your theme in state, and define your styles within the body of the component, that could be a savings in boilerplate. It's up to you whether having your styles in the component body is acceptable.
Side note, if you're already using a state manager, I would recommend not mixing it with the Context API without knowing more. It's simpler to have one solution there.

Is there a "special" syntax for adding styles to children of a React Native component?

So, in regular CSS, if I want to apply a style to all children of elements with a given id/class/element name, I would do this:
(id/class/name of parent element) * {
}
This will automatically apply to every child of the specified parent element(s) - I don't need to add any classes/ids/names, etc. to the children.
Is there an equivalent syntax in React Native? Best I can do so far is
view {
// style here
}
subelementsOfView {
}
and then add the subelementsOfView style to all children of View.
Am I wrong? Is there another syntax I can use?
You would create a StyleSheet as shown:
export const styles = StyleSheet.create({
someStyleKey: {
backgroundColor: 'red'
}
})
Wherever your children components are you can do the following:
import { styles } from '../<location-of-stylesheet>'
// Using View as an example component
<View style={styles.someStyleKey}></View>
If your child component already has a style you can also pass in an array of styles such as:
<View style={[existingStyle, styles.someStyleKey]}></View>
Whatever comes later in the style array will overwrite previous style values.

Nuxt reusable dynamic custom page transition with javascript hooks?

I have a Nuxt.js site that I'm trying to get some fancy page transitions working on. I think I understand how you're supposed to use the transition setting when it's just CSS, but how do I make it reusable with JavaScript hooks?
It seems to me we should be able to do something like this:
// In a Page.vue template
transition(to, from) {
if (!from) {
return "fade"
}
if (to.name == "directors-name-work") {
// Animate to video playing
return "to-video"
}
if (from.name == "directors-name-work") {
// Scroll to slideshow, and at same video we just came from.
return "from-video"
}
}
And then I need to be able to define what the JS hooks are for to-video and from-video in JavaScript somewhere, but I have no idea where that goes? Where does enter() and beforeEnter() hooks get defined for the separate transitions? It makes sense if we just have one transition, then I could do it in a mixin. But when it is dynamic I have no idea.
Is there a file I should be putting somewhere called transition-to-video and transition-from-video?
It's currently undocumented, but the page's transition function can return a transition object, which may include the transition JavaScript hooks. This allows you to define your shared transition objects in a common file, and import them into a page as needed:
~/transitions.js:
export default {
fade: {
name: 'fade',
mode: 'out-in',
beforeEnter(el) {
console.log('fade beforeEnter')
}
},
bounce: {
name: 'bounce',
afterEnter(el) {
console.log('bounce afterEnter')
}
},
}
~/pages/about.vue:
<script>
import transitions from '~/transitions'
export default {
transition(to, from) {
return to.query.fade ? transitions.fade : transitions.bounce
},
}
</script>

react-native prop type for text style

i have component with a simple structure and a <Text> somewhere inside the tree for which i want to pass in a style. Which works perfectly but for the proptypes validation.
The basic setup is not much more than that
export default class Component extends PureComponent {
render() {
return (<View><Text style={this.props.style}>Some text</Text></view>);
}
}
Component.defaultProps = {
style: null,
};
Component.propTypes = {
style: ViewPropTypes.style,
};
The problem is that the ViewPropTypes.style does not contain i.e. color key. So providing a style with a color is invalid and produces a warning. I tried to import TextStylePropTypes as i found in https://github.com/facebook/react-native/blob/master/Libraries/Text/TextStylePropTypes.js but it is undefined.
Any advice on what to do?
For anybody trying to achieve this seems like View.propTypes.style is deprecated while Text.propTypes.style is not.
As the passed style prop is for the Text node, use Text.propTypes.style as shown below...
Component.propTypes = {
style: Text.propTypes.style
};

How to implement a user selectable theme / style in react native?

If user has selected light-theme, and switches to dark-theme, then all scenes will immediately render to using the dark-theme.
I am using react-native-router-flux if this helps.
Thanks in advance,
Different approaches are possible. One of them is to use React context. Generally it should be used with caution but theming is one of the official examples where it is suitable.
Theming is a good example of when you might want an entire subtree to have access to some piece of information
So the example might look like
class App extends Component {
getChildContext() {
return {theme: { primaryColor: "purple" }};
}
...
}
App.childContextTypes = {
theme: React.PropTypes.object
};
where you set the context for rest of your application and then you use it in your components
class Button extends Component {
render() {
return <TouchableHighlight underlayColor={this.context.theme.primaryColor}>...
}
}
Button.contextTypes = {
theme: React.PropTypes.object
};
If you want to switch theme, you can set context based on your state/props that can be based on user selection.
Currently we are dealing with same questions and therefore we have starting prototyping library called react-native-themeable.
The idea is to use context to store theme and (re)implement RN components so they can replace original components but supports theming.
Example of theme switching you can find in https://github.com/instea/react-native-themeable/blob/master/examples/src/SwitchTheme.js
You can start by creating one JS file containing two objects that have the colors for each theme. Then just use one as a default and if the user picks another theme save it in the database or using local storage and pull the relevant object.
export const theme1 = {
blue: '#fddd',
red: '#ddddd',
buttonColor: '#fff'
}
export const theme2 = {
blue: '#fddd',
red: '#ddddd'
buttonColor: '#fff'
}
Then just import the relevant file:
import * as themes from 'Themes'
const currentTheme = this.props.currentTheme ? this.props.currentTheme : 'theme1'
const styles = StyleSheet.create({
button: {
color: themes[currentTheme].buttonColor
},
})
Wouldn’t it be great if you could import a colors object directly, and modify the object every time you change the theme and have those new colors propagate to the entire app? Then your components wouldn’t need to have any special theme logic. I was able to achieve this using a combination of AsyncStorage, forced app restart, and async module loading.