How in React MUI Tooltip add multiple text as label and sublabel - javascript

I'm adding a MaterialUI Tooltip to my React app and I need to have two text lines.
One will be treated as the title main text the other one as a sublabel.
Here in the screenshot, you can see where I stuck
The goal is to have it all in one card as
The label should read: Self-assessment opened: [n]
Sub-label: Click to drill down
An example from the Figma I have which shows how the card should look
I'm new to MUI and not sure how I should do it and this is the code I have so far
import { Box, Popper, Tooltip } from '#mui/material';
import { styled } from '#mui/material/styles';
import { useTheme } from '#mui/styles';
import { useIntl } from 'react-intl';
// Use styles from src/analytics/components/TooltipCard/TooltipCard.js to make it look the same
const TooltipCardPopper = styled(Popper)(({ theme }) => ({
'& > div': {
...theme.typography.caption,
backgroundColor: 'white',
boxShadow: theme.shadows[7],
borderRadius: '5px',
paddingLeft: theme.spacing(1.2),
paddingRight: theme.spacing(1.2),
paddingTop: theme.spacing(0.5),
paddingBottom: theme.spacing(0.5),
borderWidth: 1,
borderStyle: 'solid',
borderColor: theme.palette.grey[300],
},
}));
const calculateTotals = ({ data }) =>
data?.reduce(function (accumulator, item) {
return accumulator + item.total;
}, 0);
const CenteredMetricToolTip = ({ position, data }) => {
const theme = useTheme();
const intl = useIntl();
const show = !!position;
const total = calculateTotals({ data });
return (
<Tooltip
open={show}
disableFocusListener
disableHoverListener
disableTouchListener
disableInteractive
title={intl.formatMessage({ defaultMessage: 'Click to drill down' })}
PopperComponent={TooltipCardPopper}
TransitionProps={{ timeout: 0 }} // timeout more than 0 => transition => causes re-positioning and blinking
>
<Box
sx={{
position: 'absolute',
display: show ? 'block' : 'hide',
left: `${position?.x ?? 0}px`,
top: `${position?.y ?? 0}px`,
}}
>
{intl.formatMessage(
{ defaultMessage: ' Self-assessment opened: {total}' },
{ total },
)}
</Box>
</Tooltip>
);
};
export default CenteredMetricToolTip;

try to change title property value from title={intl.formatMessage({ defaultMessage: 'Click to drill down' })} to
title={
<div>
<div>{intl.formatMessage({ defaultMessage:"Self-assessment opened: [n]" })}<div>
<div>{intl.formatMessage({ defaultMessage:"Click to drill down"})}</div>
<div>
}
on Tooltip Component

Related

MUI's Stepper StepIconComponent prop having trouble with rendering styles from styles object. Causing app to crash

Currently trying to figure out how to render the styles(without having to do inline styles) from the styles object for the stepper component. However, it is giving me an error when I try to do something similar to what Material UI's demo gave me. I took bits and pieces from it basically and tried to implement it in my code. Here is what Material UI's demo looks like which I want to replicate as well.
And here is the code they have
const ColorlibStepIconRoot = styled('div')(({ theme, ownerState }) => ({
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.grey[700] : '#ccc',
zIndex: 1,
color: '#fff',
width: 50,
height: 50,
display: 'flex',
borderRadius: '50%',
justifyContent: 'center',
alignItems: 'center',
...(ownerState.active && {
backgroundImage:
'linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)',
boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
}),
...(ownerState.completed && {
backgroundImage:
'linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)',
}),
}));
function ColorlibStepIcon(props) {
const { active, completed, className } = props;
const icons = {
1: <SettingsIcon />,
2: <GroupAddIcon />,
3: <VideoLabelIcon />,
};
return (
<ColorlibStepIconRoot ownerState={{ completed, active }} className={className}>
{icons[String(props.icon)]}
</ColorlibStepIconRoot>
);
}
I figured I could scrap the HOC component(color step icon root) and just do without root. Also, they are importing styled from
import { styled } from '#mui/material/styles';
Which when I try to do, its undefined. So I tried to use it in the styles object the way Ive been always doing with withStyles.
But am getting this error:
Here is my code:
import React from 'react';
import { Typography } from '#material-ui/core';
import { withStyles } from '#material-ui/core/styles';
import Stepper from '#material-ui/core/Stepper';
import Step from '#material-ui/core/Step';
import StepLabel from '#material-ui/core/StepLabel';
import Icon from '#material-ui/core/Icon';
import PropTypes from 'prop-types';
const styles = theme => ({
stepLabelRoot: {
fontWeight: 'bold',
color: '#fff',
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
},
checklistHeader: {
fontWeight: 'bold',
marginTop: '80px',
color: 'white'
},
connectorIcon: {
color: theme.palette.text.secondary
},
active: {
backgroundColor: 'green'
},
stepper: {
background: 'none',
fontWeight: 'bold',
height: '500px'
},
checklistImage: {
width: '42px',
height: '42px'
}
});
const steps = ['Are you there?', 'Adopt', 'Buy'];
const Checklist = ({ classes }) => {
const ColorlibStepIcon = ({
icon, completed, className, classes, theme
}) => {
const icons = {
1: <img className={classes.checkListImage} src="https://i.pinimg.com/474x/be/54/bd/be54bd5e8e9c23e3ce570ff2acae592d.jpg" alt="check" />,
2: <img className={classes.checkListImage} src="https://i.pinimg.com/474x/be/54/bd/be54bd5e8e9c23e3ce570ff2acae592d.jpg" alt="check" />,
3: <img className={classes.checkListImage} src="https://i.pinimg.com/474x/be/54/bd/be54bd5e8e9c23e3ce570ff2acae592d.jpg" />,
};
return (
<div ownerState={{ completed }} className={className}>
{icons[String(icon)]}
</div>
);
};
return (
<React.Fragment>
<Typography variant="h6" align="center" gutterBottom className={classes.checklistHeader}>Check the following</Typography>
<Stepper alternativeLabel activeStep={2} className={classes.stepper}>
{steps.map(label => (
<Step key={label}>
<StepLabel classes={{ root: classes.stepLabelRoot }} StepIconComponent={ColorlibStepIcon}>
<div className={classes.stepLabelRoot}>
{label}
</div>
<span>
Lorem Ipsum
</span>
</StepLabel>
</Step>
))}
</Stepper>
</React.Fragment>
);
};
Checklist.defaultProps = {
};
Checklist.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(Checklist);
You have 2 bugs in your code. In your icon component:
<img className={classes.checkListImage}
The rule name you defined above is called checklistImage not checkListImage, so change it to:
<img className={classes.checklistImage}
Secondly, the classes from the Checklist component is shadowed by the classes inside ColorlibStepIcon:
const ColorlibStepIcon = ({
icon,
completed,
className,
theme,
/*classes <-- this classes is undefined which shadows the real classes
passing from above, so remove it */
}) => {

how do I build a text input in react native that has a placeholder that changes to a textview on top when clicked

I am a bit new to react native and I have an issue I need help with
how do I build a text input in react native that has a placeholder that changes to a text view on top when clicked?
Similar to the screenshot below
empty text input field looks like this in its default state
text field with data entered
see the empty input text has a placeholder appearing in the middle of the input text field
see the second diagram, the place holder text is moved to the top of the input field once the user starts typing text into the input field
The easiest way is to use react-native-paper package with their text input:
import * as React from 'react';
import { TextInput } from 'react-native-paper';
const MyComponent = () => {
const [text, setText] = React.useState('');
return (
<TextInput
label="Email"
value={text}
onChangeText={text => setText(text)}
/>
);
};
export default MyComponent;
Result:
Here is what I use without any library, working example and if you want to add animation to the fields working example with animation
import React, { Component } from 'react';
import {
View,
StatusBar,
TextInput,
Text,
} from 'react-native';
class FloatingLabelInput extends Component {
state = {
isFocused: false,
};
handleFocus = () => this.setState({ isFocused: true });
handleBlur = () => this.setState({ isFocused: false });
render() {
const { label, ...props } = this.props;
const { isFocused } = this.state;
const labelStyle = {
position: 'absolute',
left: 0,
top: !isFocused ? 18 : 0,
fontSize: !isFocused ? 20 : 14,
color: !isFocused ? '#aaa' : '#000',
};
return (
<View style={{ paddingTop: 18 }}>
<Text style={labelStyle}>
{label}
</Text>
<TextInput
{...props}
style={{ height: 26, fontSize: 20, color: '#000', borderBottomWidth: 1, borderBottomColor: '#555' }}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
blurOnSubmit
/>
</View>
);
}
}
export default class App extends Component {
state = {
value: '',
};
handleTextChange = (newText) => this.setState({ value: newText });
render() {
return (
<View style={{ flex: 1, padding: 30, backgroundColor: '#f5fcff' }}>
<StatusBar hidden />
<FloatingLabelInput
label="Email"
value={this.state.value}
onChangeText={this.handleTextChange}
/>
</View>
);
}
}

!important on makeStyle

I'm trying to display snackbar over dialog.
My dialog have an zIndex of 1500 and it must be that.
My snackbar that is a custom Component that use MaterialUI Snackbar have a zIndex of 1400 automatically and I want to change that but my method doesn't work.
const useContentStyles = makeStyles((theme: Theme) => ({
containerRoot :{
color:'blue !important',
backgroundColor: 'green !important',
zIndex: 1501,
}
}))
const App: FunctionComponent = () => {
return (
<>
<SnackbarProvider maxSnack={4} anchorOrigin={{vertical: 'bottom', horizontal: 'center'}} classes={{containerRoot: classes.containerRoot}}>
<SnackbarConsumer messageType={'error'} time={4000} />
<SnackbarConsumer messageType={'success'} time={4000} />
<SnackbarConsumer messageType={'info'} time={4000} />
<SnackbarConsumer messageType={'warning'} time={4000} />
</SnackbarProvider>;
</>
)
}
My zIndex is applied but I must to write !important to make it work but I can't do that:
const useContentStyles = makeStyles((theme: Theme) => ({
containerRoot :{
color:'blue !important',
backgroundColor: 'green !important',
zIndex: 1501 !important,
}
}))
What Can I do ?
maybe Template literals could be a solution.
const index = 1501;
containerRoot :{
color:'blue !important',
backgroundColor: 'green !important',
zIndex: `${index} !important`
}

Styling reusable components in React-Native

I made a reusable component Button.js and I'm importing it on two different screens. The button looks the same, but on the first screen I need it to be position: 'absolute' and on the second one position: 'relative' (the default).
How do I add the position to be absolute on the first screen? I tried to add the styling on FirstPage.js but it does not work. How do I overwrite the style that is defined in Button.js?
Button.js:
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ position, onPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle, {'position': position}}>
<Text style={textStyle}>{children}</Text>
</TouchableOpacity>
);
};
Button.defaultProps = {
position: 'relative',
}
const styles = {
textStyle: {
alignSelf: 'center',
color: '#F44336',
fontSize: 16,
},
buttonStyle: {
zIndex: 2,
width: 100,
backgroundColor: '#FFF',
}
};
export { Button };
You can pass props, something like this (Button.js) (edited according to posted code):
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ position, onPress, children }) => {
const { buttonStyle, textStyle } = styles;
const style = {...buttonStyle, position };
return (
<TouchableOpacity onPress={onPress} style={style}>
<Text style={textStyle}>{children}</Text>
</TouchableOpacity>
);
};
Button.defaultProps = {
position: 'relative',
}
const styles = {
textStyle: {
alignSelf: 'center',
color: '#F44336',
fontSize: 16,
},
buttonStyle: {
zIndex: 2,
width: 100,
backgroundColor: '#FFF',
}
};
export { Button };
Your button of course looks different, this is just an outline of what you could do (basically just using props).
This is REUSABLE Button as touchableOpacity.
export const NormalThemeButton = (props) => {
return (
<TouchableOpacity
style={[{ ...props.style, ...styles.normalThemeBtn }]}
style={[{ alignItems: props.align }, styles.anchor]}
onPress={props.onPress} >
<CustomText text={props.text} l bold style={{
textAlign: 'center',
color: theme['blackColor']
}} />
{props.children}
</TouchableOpacity >
);
};
This is where this RESUABLE Button is been used.
style={{ ...styles.openArrivedButton }}
text={Lng.instance.translate('useWaze')}
onPress={() => { Waze() }}/>
Hope You find it helpful.

Change button style on press in React Native

I'd like the style of a button in my app to change when it is being pressed. What is the best way to do this?
Use TouchableHighlight.
Here an example:
import React from 'react';
import { TouchableHighlight, View, Text, StyleSheet } from 'react-native';
export default function Button() {
var [ isPress, setIsPress ] = React.useState(false);
var touchProps = {
activeOpacity: 1,
underlayColor: 'blue', // <-- "backgroundColor" will be always overwritten by "underlayColor"
style: isPress ? styles.btnPress : styles.btnNormal, // <-- but you can still apply other style changes
onHideUnderlay: () => setIsPress(false),
onShowUnderlay: () => setIsPress(true),
onPress: () => console.log('HELLO'), // <-- "onPress" is apparently required
};
return (
<View style={styles.container}>
<TouchableHighlight {...touchProps}>
<Text>Click here</Text>
</TouchableHighlight>
</View>
);
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
btnNormal: {
borderColor: 'blue',
borderWidth: 1,
borderRadius: 10,
height: 30,
width: 100,
},
btnPress: {
borderColor: 'blue',
borderWidth: 1,
height: 30,
width: 100,
}
});
React Native now provides a new Pressable component that can detect various stages of press interactions.
So, in order to change the color(in general any style) of the component, refer below example:
<Pressable
style={({ pressed }) => [{ backgroundColor: pressed ? 'black' : 'white' }, styles.btn ]}>
{({ pressed }) => (
<Text style={[{ color: pressed ? 'white' : 'black' }, styles.btnText]}>
{text}
</Text>
)}
</Pressable>
Code breakdown:
style={({ pressed }) => [{ backgroundColor: pressed ? 'black' : 'white' }, styles.btn ]}
Here the style prop receives pressed(boolean) that reflects whether Pressable is pressed or not and returns an array of styles.
{({ pressed }) => (
<Text style={[{ color: pressed ? 'white' : 'black' }, styles.btnText]}>
{text}
</Text>
)}
Here the text style too can be modified as the pressed is also accessible to the children of Pressable component.
Use the prop:
underlayColor
<TouchableHighlight style={styles.btn} underlayColor={'gray'} />
https://reactnative.dev/docs/touchablehighlight
This is Besart Hoxhaj's answer in ES6. When i answer this, React Native is 0.34.
import React from "react";
import { TouchableHighlight, Text, Alert, StyleSheet } from "react-native";
export default class TouchableButton extends React.Component {
constructor(props) {
super(props);
this.state = {
pressed: false
};
}
render() {
return (
<TouchableHighlight
onPress={() => {
// Alert.alert(
// `You clicked this button`,
// 'Hello World!',
// [
// {text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
// {text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
// {text: 'OK', onPress: () => console.log('OK Pressed')},
// ]
// )
}}
style={[
styles.button,
this.state.pressed ? { backgroundColor: "green" } : {}
]}
onHideUnderlay={() => {
this.setState({ pressed: false });
}}
onShowUnderlay={() => {
this.setState({ pressed: true });
}}
>
<Text>Button</Text>
</TouchableHighlight>
);
}
}
const styles = StyleSheet.create({
button: {
padding: 10,
borderColor: "blue",
borderWidth: 1,
borderRadius: 5
}
});
use something like that :
class A extends React.Component {
constructor(props){
super(props);
this.state = {
onClicked: false
}
this.handlerButtonOnClick = this.handlerButtonOnClick.bind(this);
}
handlerButtonOnClick(){
this.setState({
onClicked: true
});
}
render() {
var _style;
if (this.state.onClicked){ // clicked button style
_style = {
color: "red"
}
}
else{ // default button style
_style = {
color: "blue"
}
}
return (
<div>
<button
onClick={this.handlerButtonOnClick}
style={_style}>Press me !</button>
</div>
);
}
}
If you use an external CSS, you can use className in place of style property :
render() {
var _class = "button";
var _class.concat(this.state.onClicked ? "-pressed" : "-normal") ;
return (
<div>
<button
onClick={this.handlerButtonOnClick}
className={_class}>Press me !</button>
</div>
);
}
It doesn't really matter how do you apply your CSS. Keep your eyes on the "handlerButtonOnClick" method.
When the state change, the component is re-rendered ("render" method is called again).
Good luck ;)

Categories