How to set height to an element by his background image height - css

Hi I have this component in my app, Right now the height of this ButonBase is hard coded.
I get an image from backend and I set that image as a backgroundImage for the ImageImagine component.
I need to make height of that ButonBase to bee dinamic so the background image in imageImagine can mentain original aspect ratio.
import React, { useState } from 'react';
import {
Box,
ButtonBase as MuiButtonBase,
IconButton,
Typography,
styled,
} from '#mui/material';
import Label from './Label';
import Favorite from './Favorite';
import MintingContextButton from './MintingContextButton';
import StatusLabel from 'src/components/StatusLabel';
import PublicLabel from 'src/components/PublicLabel';
import { IMAGINE_STATUS } from 'src/constants';
import { authDomain } from 'src/config';
const ButtonBase = styled(MuiButtonBase)(({ theme }) => ({
position: 'relative',
height: 342,
width: '100%',
borderRadius: 32,
[theme.breakpoints.down('xs')]: {
width: '100% !important', // Overrides inline-style
height: 326,
},
'&:hover': {
'& .imageTitle': {
opacity: 1,
transition: theme.transitions.create('opacity'),
zIndex: 1,
},
'& .imageBackdrop': {
opacity: 0.7,
},
'& .MuiIconButton-favorite': {
opacity: 1,
transition: theme.transitions.create('opacity'),
zIndex: 12,
},
'& .MuiButton-minting': {
opacity: 1,
transition: theme.transitions.create('opacity'),
zIndex: 12,
},
},
}));
const ContextContainer = styled('span')(() => ({
position: 'absolute',
width: '100%', // should on if real mint button
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
padding: 16,
zIndex: 1, // Remove if real mint button
}));
const StyledStatusLabel = styled(StatusLabel)(() => ({
position: 'absolute',
left: 16,
top: 16,
zIndex: 1,
}));
const MintIconButton = styled(IconButton)(() => ({
position: 'absolute',
left: 16,
top: 16,
zIndex: 1,
background: 'rgba(0, 0, 0, 0.7)',
'&:hover': {
background: 'rgba(128, 58, 254, 0.9)',
},
}));
const ImageTitle = styled('span')(({ theme }) => ({
opacity: 0,
textAlign: 'left',
// [theme.breakpoints.down('sm')]: {
// opacity: 1,
// zIndex: 1
// },
}));
const ImageBackdrop = styled('span')(({ theme }) => ({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
backgroundColor: theme.palette.common.black,
opacity: 0,
transition: theme.transitions.create('opacity'),
borderRadius: 32,
// [theme.breakpoints.down('sm')]: {
// opacity: 0.7,
// },
}));
const ImageImagine = styled('span')(() => ({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
backgroundSize: 'cover',
backgroundPosition: 'center 40%',
borderRadius: 32,
}));
const GalleryItem = ({
imagine,
imagine: {
id,
title,
status,
isMyFavorite,
public: publicStatus,
context: imgContext,
thumb_url: imgUrl,
count_favorites: countFavorites,
},
onOpen,
onClose,
...props
}) => {
const [isHoverFavorite, setHoverFavorite] = useState(false);
return (
<>
<ButtonBase
className="MuiButtonBase-gallery"
disableRipple
focusRipple
onClick={(event) => onOpen(event, id)}
>
<ContextContainer>
<Box display="flex" justifyContent="space-between">
<Box
display="flex"
visibility={status === IMAGINE_STATUS.COMPLETE && 'hidden'}
>
<StyledStatusLabel status={status} />
</Box>
{status === IMAGINE_STATUS.COMPLETE && (
<React.Fragment>
<Favorite
imagineId={id}
isMyFavorite={isMyFavorite}
isHoverFavorite={isHoverFavorite}
isHidden
onHoverFavorite={setHoverFavorite}
count={countFavorites}
/>
{/* <MintingContextButton imagine={imagine} /> */}
</React.Fragment>
)}
</Box>
<ImageTitle className="imageTitle">
<Typography color="textPrimary" variant="subtitle1" noWrap>
{title}
</Typography>
<Box
display="flex"
justifyContent="space-between"
alignItems="center"
>
{imgContext && <Label>{imgContext}</Label>}
<PublicLabel publicStatus={publicStatus} />
</Box>
</ImageTitle>
</ContextContainer>
<ImageImagine
style={{
backgroundImage: `url(${
imgUrl ?? `${authDomain}/images/glitchcat.gif`
})`,
}}
/>
<ImageBackdrop className="imageBackdrop" />
</ButtonBase>
</>
);
};
export default GalleryItem;

Had you tried to set the height of the ButtonBase into height: auto and the min-height into min-height: fit-content?

Related

How to change the button color which consists of divs on press and back?

I have a react component which must be a custom button and contains from 2 divs and 1 . My goal here is to implement a function that changes the color from white to orange after onclick and becomes white again after I click somewhere else on the screen.
This is my first react project and I tried multiple approaches already and it still doesn´t work even if the code compiles.. Any suggestions here guys?
import React from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
export default function PointMark() {
return (
<TouchableOpacity style={styles.touchPoint}>
<div style={styles.outerCircle}>
<div style={styles.innerCircle}></div>
</div>
</TouchableOpacity>
);
}
// Styles
const styles = StyleSheet.create({
touchPoint: {
width: 68,
height: 68,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 50,
border: "3px solid #ffffff",
},
outerCircle: {
width: 42,
height: 42,
borderRadius: 50,
border: "3px solid #ffffff",
position: 'relative',
},
innerCircle: {
width: 22,
height: 22,
borderRadius: 50,
backgroundColor: '#ffffff',
position: 'absolute',
top: 10,
left: 10,
}
});
How about using something like react-native-webhooks?
For your case, perhaps this:
import React from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
import { useActive } from 'react-native-web-hooks';
export default function PointMark() {
const ref = React.useRef(null);
const isActive = useActive(ref);
return (
<TouchableOpacity
ref={ref}
style={{
...styles.touchPoint,
...(isActive && styles.touchPointActive)
}}>
<div style={styles.outerCircle}>
<div
style={{
...styles.innerCircle
...(isActive && styles.innerCircleActive)
}}
/>
</div>
</TouchableOpacity>
);
}
// Styles
const styles = StyleSheet.create({
touchPoint: {
width: 68,
height: 68,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 50,
border: "3px solid #ffffff",
},
touchPointActive: {
border: "3px solid #ff8000",
},
outerCircle: {
width: 42,
height: 42,
borderRadius: 50,
border: 'inherit',
position: 'relative',
},
innerCircle: {
width: 22,
height: 22,
borderRadius: 50,
backgroundColor: '#ffffff',
position: 'absolute',
top: 10,
left: 10,
},
innerCirlceActive: {
backgroundColor: '#ff8000',
}
});
A few things to note:
I set the border property on the outerCircle to inherit, that way you don't need to define the border again
div elements that are empty may be self-closing e.g. <div />
Here's the example they use on their NPM page:
import { useRef } from 'react';
import { StyleSheet, Linking, Text, Platform } from 'react-native';
import { useHover, useFocus, useActive } from 'react-native-web-hooks';
function Link({ children, href = '#' }) {
const ref = useRef(null);
const isHovered = useHover(ref);
const isFocused = useFocus(ref);
const isActive = useActive(ref);
return (
<Text
accessibilityRole="link"
href={href}
draggable={false}
onPress={() => Linking.openURL(href)}
tabIndex={0}
ref={ref}
style={[
styles.text,
isHovered && styles.hover,
isFocused && styles.focused,
isActive && styles.active,
]}>
{children}
</Text>
);
}
const styles = StyleSheet.create({
text: {
...Platform.select({
web: {
cursor: 'pointer',
outlineStyle: 'none',
borderBottomWidth: 1,
borderBottomColor: 'transparent',
transitionDuration: '200ms',
},
default: {},
}),
},
active: {
color: 'blue',
borderBottomColor: 'blue',
opacity: 1.0,
},
hover: {
opacity: 0.6,
},
focused: {
borderBottomColor: 'black',
},
});

React Native - Pressable is not clickable on Android

What I'm building:
I'm creating a card that will render with a question mark at top of it and when the user press it, the card will flip with animation and show some information.
Code:
From a code perspective it looks like this:
import { View, StyleSheet, Text, Pressable, Animated } from 'react-native';
import { FontAwesome } from '#expo/vector-icons';
import { GlobalStyles } from '../../constants/styles';
import { useTranslation } from 'react-i18next';
export default Card = ({ isSpy, guessingItem, onPress }) => {
const { t } = useTranslation();
let currentValue = 0;
const animatedValue = new Animated.Value(0);
animatedValue.addListener((v) => (currentValue = v.value));
const frontInterpolate = animatedValue.interpolate({
inputRange: [0, 180],
outputRange: ['0deg', '180deg'],
});
const backInterpolate = animatedValue.interpolate({
inputRange: [0, 180],
outputRange: ['180deg', '360deg'],
});
const frontAnimatedStyles = {
transform: [{ rotateY: frontInterpolate }],
};
const backAnimatedStyles = {
transform: [{ rotateY: backInterpolate }],
};
const flipCard = () => {
console.log(currentValue);
if (currentValue >= 90) {
Animated.spring(animatedValue, {
toValue: 0,
tension: 10,
friction: 8,
useNativeDriver: false,
}).start();
setTimeout(() => onPress(), 600);
} else {
Animated.spring(animatedValue, {
toValue: 180,
tension: 10,
friction: 8,
useNativeDriver: false,
}).start();
}
};
return (
<View style={styles.constainer}>
<Pressable onPress={flipCard} style={{ backgroundColor: 'red' }}>
<View style={GlobalStyles.styles.flexbox}>
<Animated.View style={[styles.innerContainer, frontAnimatedStyles]}>
<FontAwesome name="question" size={160} />
</Animated.View>
</View>
</Pressable>
<Pressable onPress={flipCard}>
<View style={GlobalStyles.styles.flexbox}>
<Animated.View style={[backAnimatedStyles, styles.innerContainer, styles.innerContainerBack]}>
<View style={styles.constainer}>
{!isSpy && (
<>
<FontAwesome name={guessingItem.section.icon} size={60} />
<Text style={styles.itemName}>{guessingItem.name}</Text>
</>
)}
{isSpy && (
<>
<FontAwesome name="user-secret" size={60} />
<Text style={styles.placeName}>{t('youAreSpy')}</Text>
</>
)}
</View>
</Animated.View>
</View>
</Pressable>
</View>
);
};
const styles = StyleSheet.create({
constainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
innerContainer: {
height: 300,
width: 230,
marginVertical: 50,
padding: 60,
borderWidth: 6,
borderColor: GlobalStyles.colors.primary50,
borderRadius: 20,
justifyContent: 'center',
alignItems: 'center',
backfaceVisibility: 'hidden',
},
innerContainerBack: {
position: 'absolute',
right: -115,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
},
itemName: {
marginTop: 20,
fontSize: 18,
alignItems: 'center',
color: GlobalStyles.colors.primary50,
},
pressed: {},
});
What is an issue:
On-screen below you can see a pressable element with red background.
If I click on any part of this red part, the card would flip. If I test it on Android, clicking on anything inside the white border would not trigger a flip. Only clicking outside of that white border but still inside the red background would trigger a flip.
The question is: Why it behaves differently when I am using basic react-native elements? How can I fix that so clicking would always work for the inside click?
I tested this component on my side and it works well. I think there is no problem with the Card component. Please check the parent component of the Card.
I only changed "right" value from -115 to 0 in the style of innerContainerBack.
innerContainerBack: {
position: 'absolute',
right: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
}
And you'd better use only one Pressable Component and remove the View component in the Pressable. So my ultimate solution is
import { View, StyleSheet, Text, Pressable, Animated } from 'react-native';
import { FontAwesome } from '#expo/vector-icons';
import { GlobalStyles } from '../../constants/styles';
import { useTranslation } from 'react-i18next';
export default Card = ({ isSpy, guessingItem, onPress }) => {
const { t } = useTranslation();
let currentValue = 0;
const animatedValue = new Animated.Value(0);
animatedValue.addListener((v) => (currentValue = v.value));
const frontInterpolate = animatedValue.interpolate({
inputRange: [0, 180],
outputRange: ['0deg', '180deg'],
});
const backInterpolate = animatedValue.interpolate({
inputRange: [0, 180],
outputRange: ['180deg', '360deg'],
});
const frontAnimatedStyles = {
transform: [{ rotateY: frontInterpolate }],
};
const backAnimatedStyles = {
transform: [{ rotateY: backInterpolate }],
};
const flipCard = () => {
console.log(currentValue);
if (currentValue >= 90) {
Animated.spring(animatedValue, {
toValue: 0,
tension: 10,
friction: 8,
useNativeDriver: false,
}).start();
setTimeout(() => onPress(), 600);
} else {
Animated.spring(animatedValue, {
toValue: 180,
tension: 10,
friction: 8,
useNativeDriver: false,
}).start();
}
};
return (
<View style={styles.constainer}>
<Pressable onPress={flipCard} style={{ backgroundColor: 'red' }}>
<Animated.View style={[styles.innerContainer, frontAnimatedStyles]}>
<FontAwesome name="question" size={160} />
</Animated.View>
<Animated.View style={[backAnimatedStyles, styles.innerContainer, styles.innerContainerBack]}>
<View style={styles.constainer}>
{!isSpy && (
<>
<FontAwesome name={guessingItem.section.icon} size={60} />
<Text style={styles.itemName}>{guessingItem.name}</Text>
</>
)}
{isSpy && (
<>
<FontAwesome name="user-secret" size={60} />
<Text style={styles.placeName}>{t('youAreSpy')}</Text>
</>
)}
</View>
</Animated.View>
</Pressable>
</View>
);
};
const styles = StyleSheet.create({
constainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
innerContainer: {
height: 300,
width: 230,
marginVertical: 50,
padding: 60,
borderWidth: 6,
borderColor: GlobalStyles.colors.primary50,
borderRadius: 20,
justifyContent: 'center',
alignItems: 'center',
backfaceVisibility: 'hidden',
},
innerContainerBack: {
position: 'absolute',
right: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
},
itemName: {
marginTop: 20,
fontSize: 18,
alignItems: 'center',
color: GlobalStyles.colors.primary50,
},
pressed: {},
});

Understanding CSS triangles and rhombus interactions in React native with absolute positions

I have a complex structure diagram with Rhombuses and triangles. I was able to create the structure using CSS tricks and absolute position property.
I want each rhombus and triangle to be clickable but the behavior is not as expected given how CSS triangles work with the borders.
An output image with some markers
In this image we have a rhombus and two triangles,
What I want:
On clicking at A,B,E - rhombus is clicked
On clicking C,D - first triangle (numbered 2 in picture) is clicked.
What happens instead:
On clicking A, nothing happens (I suspect the absolute and transform property here)
On clicking B, first triangle (numbered 2 in picture) is clicked. It is because of the transparent right border of first triangle.
On clicking C, second triangle (numbered 3 in picture) is clicked. It is because of the transparent top border of second triangle.
On clicking D, first triangle is clicked which is the expected behaviour.
On clicking E, rhombus is clicked which is the expected behaviour.
How can I make such complex interactive patterns with series of such shapes? Shall I consider using images/SVGs instead of CSS shapes? I also need to add multiple dynamic count of numbers/text/emojis in each shape.
Here's a simplified snippet of code:
import React from 'react';
import {
View,
TouchableOpacity,
StyleSheet,
SafeAreaView,
} from 'react-native';
const MyComplexDiagram = ({navigation, route}) => {
const clickShape = text => {
console.log('clicked: ', text);
};
return (
<SafeAreaView style={{flex: 1}}>
<View>
<TouchableOpacity onPress={() => clickShape("rhombus)}>
<View style={[styles.rhombus]} />
</TouchableOpacity>
<TouchableOpacity onPress={() => clickShape("first triangle")}>
<View style={[styles.firstTriangle]} />
</TouchableOpacity>
<TouchableOpacity onPress={() => clickShape("second triangle")}>
<View style={[styles.secondTriangle]} />
</TouchableOpacity>
</SafeAreaView>
);
};
export default MyComplexShape;
const styles = StyleSheet.create({
rhombus: {
position: 'absolute',
top: 50,
left: 100,
width: 100,
height: 100,
backgroundColor: 'green',
transform: [{rotate: '45deg'}],
},
firstTriangle: {
position: 'absolute',
top: 0,
left: 0,
backgroundColor: 'transparent',
borderStyle: 'solid',
borderLeftWidth: 50,
borderRightWidth: 50,
borderTopWidth: 50,
borderLeftColor: 'transparent',
borderRightColor: 'transparent',
borderTopColor: 'red',
}),
secondTriangle: {
position: 'absolute',
top: 0,
left: 0,
backgroundColor: 'transparent',
borderStyle: 'solid',
borderLeftWidth: 50 * Math.sqrt(2),
borderTopWidth: 50 * Math.sqrt(2),
borderBottomWidth: 50 * Math.sqrt(2),
borderLeftColor: 'black',
borderBottomColor: 'transparent',
borderTopColor: 'transparent',
}
});
Im not sure if the same thing happens in a browser context, but the issue with the css trick is that although the view appears to be a triangle, it is actually still a rectangle. Giving the triangles a non-transparent background color will demonstrate this. The middle triangle is intercepting the first triangle presses because its hidden rectangle entirely overlaps the first triangle. (Here's a demo showing that). You can overcome this by the other TouchableOpacities a higher zIndex than the middle one:
import React, { useMemo, useEffect, useRef, useState } from 'react';
import {
View,
TouchableOpacity,
StyleSheet,
SafeAreaView,
useWindowDimensions,
Button,
Text
} from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
withSequence,
withRepeat,
cancelAnimation,
withDelay,
} from 'react-native-reanimated';
const getHypotenuse = (side1, side2) => {
if (!side2) side2 = side1;
return Math.sqrt(side1 ** 2 + side2 ** 2);
};
const startRotation = 270;
const MyComplexDiagram = ({ navigation, route }) => {
const [animationIsRunning, setAnimationIsRunning] = useState(false);
const rotation = useSharedValue(startRotation);
const backgroundColor = useSharedValue('rgba(0,0,0,0)');
const { width, height } = useWindowDimensions();
const rotationStyle = useAnimatedStyle(() => {
return {
transform: [{ rotate: `${rotation.value}deg` }],
};
});
const colorStyle = useAnimatedStyle(() => {
return {
backgroundColor: backgroundColor.value,
};
});
const { rhombusStyle, middleTriangleStyle, leftTriangleStyle } =
useMemo(() => {
const remainingWidth =
width - styles.container.padding - styles.shapeContainer.padding;
const rhombusSize = remainingWidth * 0.3;
const rhombusHypotenuse = getHypotenuse(rhombusSize);
const rhombusLeft = remainingWidth - rhombusHypotenuse;
const rhombusTop = 25;
const middleLeft = rhombusLeft - rhombusSize;
const leftLeft = middleLeft;
return {
rhombusStyle: {
width: rhombusSize,
height: rhombusSize,
left: rhombusLeft,
top: rhombusTop,
},
middleTriangleStyle: {
borderWidth: rhombusSize * 0.8,
borderLeftWidth: rhombusSize * 0.8,
left: rhombusLeft - rhombusSize * 1.1,
top: 10,
},
leftTriangleStyle: {
borderWidth: rhombusSize,
borderBottom: rhombusSize,
left: rhombusLeft - rhombusHypotenuse * 1.7,
top: 0,
},
};
}, [width]);
const clickShape = (text) => {
console.log('clicked: ', text);
};
const toggleAnimation = () => {
if (animationIsRunning) {
backgroundColor.value = withTiming('rgba(0,0,0,0)');
} else {
backgroundColor.value = withRepeat(
withSequence(
withTiming('rgba(255,0,0,1)', { duration: 2000 }),
withTiming('rgba(0,0,0,0'),
withDelay(4000,withTiming('rgba(0,0,0,0'))
),
-1
);
}
setAnimationIsRunning((prev) => !prev);
};
return (
<SafeAreaView style={styles.container}>
<Button
title={`${animationIsRunning ? 'Hide' : 'Show'} Triangle Background`}
onPress={toggleAnimation}
/>
<Text style={{zIndex:5}}>{animationIsRunning ? 'Using zIndex to force black triangle to be on top of orange':'Default behavior without zIndex changes'}</Text>
<View style={styles.shapeContainer}>
<TouchableOpacity
style={animationIsRunning && { zIndex: 5 }}
onPress={() => clickShape('leftTriangle')}>
<Animated.View
style={[styles.leftTriangle, leftTriangleStyle, colorStyle]}
/>
</TouchableOpacity>
<TouchableOpacity
style={animationIsRunning && { zIndex: 4 }}
onPress={() => clickShape('middleTriangle')}>
<Animated.View
style={[
styles.middleTriangle,
middleTriangleStyle,
rotationStyle,
colorStyle,
]}
/>
</TouchableOpacity>
<TouchableOpacity
style={animationIsRunning && { zIndex: 5 }}
onPress={() => clickShape('rhombus')}>
<Animated.View style={[styles.rhombus, rhombusStyle]} />
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
export default MyComplexDiagram;
const styles = StyleSheet.create({
container: {
flex: 1,
// alignItems:'center',
justifyContent: 'center',
padding: 8,
},
shapeContainer: {
padding: 10,
},
rhombus: {
transform: [{ rotate: '45deg' }],
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
backgroundColor: 'green',
},
middleTriangle: {
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
width: 0,
height: 0,
borderColor: 'transparent',
borderRightColor: 'orange',
},
leftTriangle: {
position: 'absolute',
transform: [{ rotate: '225deg' }],
top: 0,
bottom: 0,
right: 0,
left: 0,
width: 0,
height: 0,
borderColor: 'transparent',
borderLeftColor: 'black',
},
});

Material UI Advanced Button - Text Alignment for Small Screensizes

React / Material-UI Novice here. I am trying to configure a set of buttons inside my app Bar that have a background picture to make it look a little cleaner. I have used a lot of code from examples online (shock) and got it to a place where i am happy with how it has formatted on a full size view (md++). However, when i downsize it to a small breakpoint though, the button image then stack instead (which is what i want) but i lose my text to the left. I have tried shifting to the right in many different ways but i dont think thats the right way to do it, is there something i am missing in making the text flex, i want the text to be in the middle?
import React from 'react'
import { AppBar, Toolbar } from "#mui/material";
import { makeStyles } from '#mui/styles'
import Button from '#mui/material/Button'
import Stack from '#mui/material/Stack'
import ButtonBase from '#mui/material/ButtonBase';
import { styled } from '#mui/material/styles';
import Typography from '#mui/material/Typography';
import Box from '#mui/material/Box';
const useStyles = makeStyles(theme => ({
button: {
...theme.typography.mainmenu,
borderRadius: "40px",
marginLeft: "1px",
height: "45px",
"&:hover": {
backgroundColor: theme.palette.secondary
}
},
}))
const images = [
{
url: '/assets/breakfastMenu.jpg',
title: 'Breakfast',
width: '33.33%',
},
{
url: '/assets/steak.jpg',
title: 'Mains',
width: '33.33%',
},
{
url: '/assets/desserts.jpg',
title: 'Desserts',
width: '33.33%',
},
];
const Image = styled('span')(({ theme }) => ({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
color: theme.palette.common.primary,
}));
const ImageButton = styled(ButtonBase)(({ theme }) => ({
position: 'relative',
height: 150,
[theme.breakpoints.down('sm')]: {
width: '100% !important', // Overrides inline-style
height: 100,
},
'&:hover, &.Mui-focusVisible': {
zIndex: 1,
'& .MuiImageBackdrop-root': {
opacity: 0.15,
},
'& .MuiImageMarked-root': {
opacity: 0,
},
'& .MuiTypography-root': {
border: '4px solid currentColor',
},
},
}));
const ImageSrc = styled('span')({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
backgroundSize: 'cover',
backgroundPosition: 'center 40%',
});
const ImageBackdrop = styled('span')(({ theme }) => ({
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
backgroundColor: theme.palette.common.black,
opacity: 0.4,
transition: theme.transitions.create('opacity'),
}));
const ImageMarked = styled('span')(({ theme }) => ({
height: 3,
width: 18,
backgroundColor: theme.palette.common.white,
position: 'absolute',
bottom: -2,
left: 'calc(50% - 9px)',
transition: theme.transitions.create('opacity'),
}));
const Header = () => {
const classes = useStyles();
return (<React.Fragment><AppBar position="sticky" className={classes.appBar}>
<Toolbar disableGutters className={classes.mainToolbar} sx={{ justifyContent: "center" }}>
<Stack direction="row" justifyContent="space-between" alignItems="center" spacing={10}>
{/* <Button variant="contained" color="secondary" className={classes.button}>Breakfast</Button>
<Button variant="contained" color="secondary" className={classes.button}>Mains</Button>
<Button variant="contained" color="secondary" className={classes.button}>Desserts</Button> */}
<Box sx={{ display: 'flex', flexWrap: 'wrap', minWidth: 900, width: '100%' }}>
{images.map((image) => (
<ImageButton
focusRipple
key={image.title}
style={{
width: image.width,
}}
>
<ImageSrc style={{
backgroundImage: `url(${image.url})`
}} />
<ImageBackdrop className="MuiImageBackdrop-root" />
<Image>
<Typography
component="span"
variant="subtitle1"
color="white"
fontWeight="bold"
sx={{
position: 'relative',
p: "7em",
pt: "2em",
pb: (theme) => `calc(${theme.spacing(1)} + 6px)`,
}}
>
{image.title}
<ImageMarked className="MuiImageMarked-root" />
</Typography>
</Image>
</ImageButton>
))}
</Box>
</Stack>
</Toolbar>
</AppBar>
</React.Fragment >
)
}
export default Header
I have moved on from this, but in case anybody finds it, using MUI i completely adapted my application by using:
import useMediaQuery from '#mui/material/useMediaQuery'
and some example like:
const matches = useMediaQuery(theme.breakpoints.down("md"))
to control when the application changes its styles

How to move an element to bottom of div

I am trying to implement waves image at the bottom of the screen as shown in image below. I have tried alignSelf:'flex-end' but it does not work. If i give top with dimensions then if screen size change image top also change. how to implement waves image at the perfect bottom?
I have also tried svg but could not make it work.
Here is my code
import React from 'react';
import {
View,
Text,
Dimensions,
TextInput,
StyleSheet,
Image,
} from 'react-native';
import database from '#react-native-firebase/database';
import auth from '#react-native-firebase/auth';
import Otp from '../assets/otp.svg';
import Waves from '../assets/waves.svg';
import {Icon} from 'native-base';
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
const Login = () => {
return (
<View style={styles.container}>
<View style={styles.view1}>
<View style={styles.header}>
<Icon type="AntDesign" name="arrowleft" style={styles.icon} />
<View style={styles.headerView}>
<Text style={styles.headerText}>OTP Verification</Text>
</View>
</View>
<Otp width={250} height={130} style={{top: -40}} />
</View>
<View style={styles.view2}>
<View style={styles.mainDiv}>
<View style={styles.loginForm}></View>
<View style={styles.iconDiv}></View>
</View>
<View style={styles.waves}>
{/* <Waves /> */}
<Image
style={styles.wavesImg}
source={require('../assets/waves.png')}
/>
</View>
</View>
</View>
);
};
export default Login;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'red',
},
view1: {
flex: 1,
backgroundColor: '#e69545',
alignItems: 'center',
justifyContent: 'space-around',
},
view2: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
},
header: {
// backgroundColor: 'red',
flexDirection: 'row',
justifyContent: 'space-around',
},
headerView: {alignItems: 'center', width: '80%'},
headerText: {color: '#fff', fontSize: 27},
icon: {
color: '#fff',
// width: 40,
fontSize: 35,
},
mainDiv: {
backgroundColor: '#fff',
width: (windowWidth / 10) * 8,
height: (windowHeight / 100) * 40,
position: 'absolute',
borderRadius: 25,
top: -60,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.3,
shadowRadius: 4.65,
elevation: 8,
},
waves: {
// // height: 300,
// position: 'absolute',
// bottom: 0,
// backgroundColor: 'green',
// position: 'absolute',
// top: (windowHeight / 10) * 3.1,
width: '100%',
height: 130,
// alignSelf: 'flex-end',
marginTop: (windowHeight / 10) * 3,
},
wavesImg: {
width: '100%',
height: 130,
},
});
I think you should try to put the style for the waves like this:
waves: {
height: 130,
width: windowWidth,
bottom: 0,
position: 'absolute'
}

Resources