How to conditionally change a color of a row in detailslist? - office-ui-fabric

I'm looking at customitemrows but there isn't much documentation.
I have a table and if a row was created by a current user, I want to change the color from black to grey. I can do that with style. I understand how to conditionally change color in customitemcolumns but can't extrapolate it to rows.
I got to:
_onRenderRow = (props) => {
return props.item['creatorUid'].match("QDN6k4pLXkea2qRM9mS7vM6whBE3")?
<DetailsRow {...props} style={{color:"#FF0000"}}/>
:
<DetailsRow {...props}/>
}
but the color doesn't change

<DetailsList
items={ items }
columns={ columns }
onRenderRow={ (props, defaultRender) => (
<div className='red'>
{defaultRender({...props, className: 'red'})}
</div>
) }
/>
<DetailsList
items={ items }
columns={ columns }
onRenderRow={ (props, defaultRender) => (
<div className='red'>
{defaultRender({...props, styles: {root: {background: 'red'}}})}
</div>
) }
/>
https://codepen.io/vitalius1/pen/pQmpVO
Here you can see 2 methods achieve what you ask for.
First is passing a regular className and have it override the default styles. If you need to override the hover states or anything else you would have to inspect in dev tools and target the appropriate classes.
Second is what is actually recommended and used internally to apply the default styles. With this method when you want to override the hover states or anything else, you would need to provide styles to each style area (in the example root is one of them). For a list of style areas available to each row follow this link. For an example on usage of the selectors for hover states follow this link.
Note: With the second method you can also pass a style function to make use of the IDetailsRowStyleProps as seen here. This way you can have a very dynamic style depending on the state of the component

Related

NativeBase: How to set colorScheme of Input?

I want to change the colorScheme of a NativeBase Input component.
Other components, like button, slider or checkbox, have a prop "colorScheme" which, if set, changes all the associated colors of that component. Input does not have that prop.
These approaches would technically work:
Setting colors for border, background etc. manually
-> But it would be a lot or work and pretty ugly
Changing the primary color in the theme
-> But maybe I want to have two different color schemes for Input on the same page, so it would not make sense to change the theme.
So, what is the best way to easily change all the associated colors of an Input component, without setting all colors manually or changing the overall theme?
I've never used NativeBase ( but now I'll take a look, thanks for this discovery... )
I highly recommend you to have a read at the Customizing Components doc which provide a way to do what you're looking for...
You can create a "variant" which is a predefined theme for a specific component. You have to define it in your customized theme ( If you don't use a <NativeBaseProvider theme={theme} /> yet check this )
export default function () {
const theme = extendTheme({
components: {
Input: {
variants: {
otherColorInput: ({ colorScheme }) => {
return {
bg: /*otherColorToSet*/ ,
};
},
},
},
},
});
return (
<NativeBaseProvider theme={theme}>{/* components */}</NativeBaseProvider>
);
};
Then you can call you new Input like this :
<Input variant="otherColorInput">

React-leaflet problem to create <Marker> <Popup> instance dynamic

I would like to create a react-leaflet object dynamically. Normal leaflet objects work, but react-leaflet do not.
Code example on:
https://codesandbox.io/s/show-problem-react-leaflet-marker-popup-object-hm0o8?file=/src/MapView.js
Left click shows the desired behavior with leaflet objects and right click the problem with react-leaflet.
problem code:
var lat = e.latlng.lat;
var lon = e.latlng.lng;
// create popup contents
// use <Marker> from react-leaflet
var newMarker = <Marker position={[lat, lon]}>
{/* use Edit Popup */}
<Popup editable open>
Your stylable content here.
</Popup>
</Marker>;
// Problem addTo(map)
newMarker.addTo(map);
newMarker is a react element. You can't call the leaflet method addTo on it, because it is not a leaflet L.Marker instance.
If you want to be able to manage the markers through react, you would need to keep a state variable which is an array of coordinates. On map click, you can add the coordinate to that array, and then render a series of <Marker /> elements from that.
In your event handlers, you're simply going to capture the position of the click and pass it to a callback setMarkers:
function MyRightClickEventHandler({ setMarkers }) {
useMapEvents({
contextmenu: (e) => {
setMarkers(e.latlng);
}
});
return null;
}
setMarkers is a callback to setState on your primary MapView component, which adds the latlng to the state variable, which contains an array of latlngs:
// inside you'r MapContainer:
<MyRightClickEventHandler
setMarkers={(markers) =>
this.setState({
MarkerArray: [...this.state.MarkerArray, markers]
})
}
/>
Then map over the latlngs that are in that state variable, if there are any:
{this.state.MarkerArray &&
this.state.MarkerArray.map((latlng) => (
<Marker position={latlng}>
<Popup editable removable>
Thanks for using my editable popup plugin!
</Popup>
</Marker>
))}
Working codesandbox
Note that if you're going to use the editable, removable, or open props on editable popups rendered dynamically from an array, be sure to read my section on using editable popups rendered from a dynamic state array - it can get hairy if you're not careful. Feel free to ask questions in the comments if you run into problems.

React Native Styling Precedence

This question is about using an array arg for the styling prop on a react component:
style={[styles.localTextStyle, textStyle...]}
As I understand precedence is from last element to first. So in the example above textStyle would overwrite styles.localTextStyle. This is good, however, I am making a custom component and I want to be able to specify inline props from the parent and have the inline be of highest precedence yet not overwrite previous styles if no prop is provided.
For example, if I were writing a custom component called Text:
<Text style={[styles.localTextStyle, textStyle, {
color: color
}]}>
I would use localTextStyle as defaults then styling passed from parent called textStyle, and finally the prop called color to set the color. This only works when the prop color is defined, otherwise, it will overwrite color to unset despite it possibly being set in textStyle for earlier styling.
So I'm wondering what the best way to circumvent this is. I currently have wrapped the final arg in a function called Clean which returns a new object with only defined keys-values. That works but it makes the code messy and I'd be shocked if someone didn't have a smarter, better way to do this.
<Text style={[styles.localTextStyle, textStyle, Clean({
color: color
})]}>
It's written inside the Documentation that :
You can also pass an array of styles - the last style in the array has precedence, so you can use this to inherit styles.
And I checked and It's like that :
[Component-Style] < [inside-array] < [outside-the-array]
like this :
TSButton has it's own styling in it's declaration
<TSButton style={[Style.button,{padding:0,width:50,height:20}]} />
So here the priority is as >>
TSButton Styling < Style.button < padding , width, ...

Simplified style change onPress React Native

The following is a first attempt at learning to simply change the style of an element onPress in react native. Being well versed in web languages I am finding it difficult as it is not as straight forward.
For reasons as yet unknown, the element requires two clicks in order to execute.
export class NavTabItem extends React.Component {
constructor(props) {
super(props);
this.state = {
active: false
}
this.NavTabAction = this.NavTabAction.bind(this)
}
NavTabAction = (elem) => {
elem.setState({active: !elem.state.active})
}
render() {
return (
<TouchableOpacity
style={this.state.active ? styles.NavTabItemSelected : styles.NavTabItem}
onPress={()=> {
this.NavTabAction(this)
}}>
<View style={styles.NavTabIcon} />
<Text style={styles.NavTabLabel}>{this.props.children}</Text>
</TouchableOpacity>
);
}
}
Other issues:
I also have not worked out how a means of setting the active state to false for other elements under the parent on click.
Additionally, Is there a simple way to affect the style of child elements like with the web. At the moment I cannot see a means of a parent style affecting a child element through selectors like you can with CSS
eg. a stylesheet that read NavTabItemSelected Text :{ // active style for <Text> }
Instead of calling elem.setState or elem.state, it should be this.setState and elem.state.
NavTabAction = (elem) => {
this.setState(prev => ({...prev, active: !prev.active}))
}
And instead of passing this in the onPress, you should just pass the function's reference.
onPress={this.NavTabAction}>
You should also remove this line because you are using arrow function
// no need to bind when using arrow functions
this.NavTabAction = this.NavTabAction.bind(this)
Additionally, Is there a simple way to affect the style of child elements like with the web
You could check styled-component, but I think that feature don't exists yet for react native. What you should do is pass props down to child components.
Thanks to everyone for their help with this and sorting out some other bits and pieces with the code.
The issue in question however was that the style was changing on the second click. A few hours later and I have a cause and a solution for anyone suffering from this. Should any of the far more experienced people who have answered this question believe this answer is incorrect or they have a better one, please post it but for now here is the only way I have found to fix it.
The cause:
Using setState was correctly re rendering the variables. This could both be seen in the console via console.log() and directly outputted in the render making them visible.
However, no matter what was tried, this did not update the style. Whether it was a style name from the Stylesheet or inline styles, they would update on the second click rather than the first but still to the parameters of the first. So if the first click should make a button turn from red to green, it would not do so even though the new state had rendered. However if a subsequent click should have turned the button back to red then the button would now go green (like it should have for the first click). It would then go red on the third click seemingly always one step behind the status passed to it.
Solution
To fix this, take the style off the the primary element (forgive terminology, someone edit), in my case, the TouchableOpacity element. Add in a child View element and place the styles on that View element instead along with the ternary operator and wallah.
It seems any change to status on the effective master element or container if you prefer, only takes affect after another render, not that contained in setStatus.
Final code:
export class NavTabItem extends React.Component {
constructor(props) {
super(props);
this.state = {
active: false
}
}
NavTabAction = () => {
this.setState({active: !this.state.active})
}
render() {
this.state.active == true ? console.log("selected") : console.log("unselected")
return (
<TouchableOpacity onPress={this.NavTabAction}>
// added View containing style and ternary operator
<View style={this.state.active == true ? styles.NavTabItemSelected : styles.NavTabItem}>
<View style={styles.NavTabIcon} />
<TextCap11 style={styles.NavTabLabel}>{this.props.children}</TextCap11>
</View>
// End added view
</TouchableOpacity>
);
}
}

Get CSS property values from a component's "style" prop

I'm writing a React Native component for a library and I want users to be able to style it using the style property, just like React.View and other built-in components.
However, since my component is actually made up of a few nested views, I need to do some calculations to figure out what styling to put on the inner ones. For example, I might need to adjust the sizing of an image based upon the thickness of a border around it, or adjust a highlight color based upon the given text color, or in some other way infer some piece of styling from another piece of styling.
To do this, I need to be able to extract the actual CSS properties (like borderWidth: 2 or backgroundColor: 'pink') out of whatever gets passed as the style prop. This is fine as long as it comes as a plain object, but it may also be the result of a call to React.StyleSheet.create. This seems to be an opaque object with all selectors simply mapped to numeric IDs.
How can I resolve these and get the actual CSS properties, in order to do anything more complicated with them than simply passing them straight on to a View?
The built-in StyleSheet.flatten function (or the identical flattenStyle function) can turn anything that can legitimately be passed to the style prop into an object mapping CSS property names to values. It works on plain objects, IDs returned by StyleSheet.create(), and arrays.
Example usage to check the width specified in the style prop from within a Component definition:
import { StyleSheet } from 'react-native'
// ... then, later, e.g. in a component's .render() method:
let width = StyleSheet.flatten(this.props.style).width;
You need to import StylesheetRegistry:
StyleSheetRegistry = require("../../node_modules/react-native/Libraries/StyleSheet/StyleSheetRegistry"),
Then pass in the style ID:
var style = StyleSheetRegistry.getStyleByID(this.props.style)
Please have a look on https://github.com/vitalets/react-native-extended-stylesheet#underscored-styles
Style created via extended stylesheet contains original values in underscored prop:
const styles = EStyleSheet.create({
text: {
fontSize: '1rem',
color: 'gray'
}
});
In runtime:
styles = {
text: 0,
_text: {
fontSize: 16,
color: 'gray'
}
}