How can I give a shadow to the TouchableOpacity in React Native? - reactjs

I am trying to apply shadow to TouchableOpacity in React native. I used both styled-components and inline style.
I have a View component called PaintCon and PainDummy and a TouchableOpacity component called PaintBtn.
I applied shadow to PaintBtn. But the strange thing is that the shadow works just fine, but PaintBtn shows a faint square box that I don't know. Use elevation to get this square. How do I get rid of this?
Below is my code.
const PaintCon = styled.View`
flex-direction: row;
justify-content: center;
align-items: center;
flex:1;
`;
const PainDummy = styled.View`
width: 20%;
justify-content: center;
align-items: center;
flex:1;
`;
const PaintBtn = styled.TouchableOpacity`
width: 80%;
height: 70px;
background-color: lightcyan;
border-radius: 18px;
margin-bottom: 5px;
`;
return (
<PaintCon
>
<PainDummy
>
<PaintBtn
style={{backgroundColor:'#0097E8',
shadowColor: '#52006A',
shadowOffset: {width: 10, height: 3},
shadowOpacity: 50,
elevation: 10,
}}
activeOpacity={0.7}>
</PaintBtn>
<Text>#0097E8</Text>
</PainDummy>
</PaintCon>
)

It looks like you've given it a different background color (lightCyan in the PaintBtn styled component style). If you remove that background color, it should work?

You don't need to use TouchableOpacity like that. Refer my example given below,
<TouchableOpacity style={styles.card}>
{{------My Codes-----}}
</TouchableOpacity>
And the styles are,(For your reference I had set the ShadowColor to green),
const styles = StyleSheet.create({
card: {
backgroundColor: "#FFFFFF",
padding: 15,
margin: 10,
borderRadius: 15,
shadowColor: "green",
elevation: 15,
flexDirection: "row",
flex: 1,
justifyContent: "space-between"
}

Related

How to add a label to a border in mui?

I would like to have a list wrapped in a border which looks and behaves the same as a textfield border:
Example textfield and list which should have both same border.
In the image, the border around the list looks similar than the one around the textfield but most notably, the label is missing. How can I add the label and how would I set up the focus listeners to get the same hover and selection behaviour?
The typescript code for the list:
<List dense sx={{ borderRadius: 1, border: 1, borderColor: 'grey.600'}}>
<ListItem secondaryAction={<IconButton edge="end" aria-label="delete"><DeleteIcon /></IconButton>}>
<ListItemText primary="primary" secondary="group id"/>
</ListItem>
</List>
I am also open for alternative approaches. Thanks for the help.
Here is my answer using React and Mui (only for icon).
It relies on flex.
We have a main container that only draws its left, bottom and right borders.
Then we have a header container in charge of drawing the top border in two parts (before and after) and a section with an icon and title.
You can either pass an icon and a title, just a title, just an icon, or nothing at all.
borderedSection.js:
import React from "react";
import SvgIcon from "#mui/material/SvgIcon";
import styles from "./borderedSection.module.scss";
function BorderedSection({ icon, title, children }) {
return (
<div className={styles.mainContainer}>
<div className={styles.header}>
<div className={styles.headerBorderBefore}></div>
{(icon || title) && (
<div className={styles.headerTitle}>
{icon && <SvgIcon component={icon} />}
{title && <span className={styles.title}>{title}</span>}
</div>
)}
<div className={styles.headerBorderAfter}></div>
</div>
<div className={styles.childrenContainer}>{children}</div>
</div>
);
}
export default BorderedSection;
borderedSection.module.scss:
$border-color: #b2b2b2;
.mainContainer {
display: flex;
flex-direction: column;
max-width: 100%;
border-left: 1px solid $border-color;
border-bottom: 1px solid $border-color;
border-right: 1px solid $border-color;
border-radius: 5px;
margin: 1em;
.childrenContainer {
padding: 1em;
}
.header {
display: flex;
flex-direction: row;
width: 100% !important;
.headerBorderBefore {
border-top: 1px solid $border-color;
width: 1em;
border-top-left-radius: 5px;
}
.headerTitle {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
gap: 0.25em;
width: fit-content;
height: 2em;
margin: -1em 0.5em 0em 0.5em;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1em;
font-weight: 600;
}
.headerBorderAfter {
border-top: 1px solid $border-color;
width: 1em;
flex-grow: 2;
border-top-right-radius: 5px;
}
}
}
usage:
import React from "react";
import BorderedSection from "./borderedSection";
import InfoIcon from "#mui/icons-material/Info";
function Example() {
return (
<div style={{ padding: "2em" }}>
<BorderedSection icon={InfoIcon} title="Icon and title">
<div>a first child with quite a long text</div>
<div>a second child</div>
</BorderedSection>
<BorderedSection title="Title only">
<div>a first child with quite a long text</div>
<div>a second child</div>
</BorderedSection>
<BorderedSection icon={InfoIcon} >
<div>Icon only</div>
<div>a second child with quite a long text</div>
</BorderedSection>
<BorderedSection >
<div>No icon and no title</div>
<div>a second child with quite a long text</div>
</BorderedSection>
</div>
);
}
Here is how it looks:
I hope it helps
I now managed to hack a solution which looks the same. I do still hope though that there is a clean way to do this: result.
<FormLabel style={{marginLeft: "0.71em", marginTop: "-0.71em", paddingLeft: "0.44em", zIndex: 2, width: "4.2em", backgroundColor: "#383838", position: "absolute", fontSize: "0.75em"}}>Damage</FormLabel>
<List dense sx={{ borderRadius: 1, border: 1, borderColor: 'grey.600', "&:hover": { borderColor: 'grey.200' }}}>
<ListItem secondaryAction={<IconButton edge="end" aria-label="delete"><DeleteIcon /></IconButton>}>
<ListItemText primary="primary" secondary="group id"/>
</ListItem>
</List>
I needed the same thing. As I was poking around I noticed that MUI accomplished this by using the fieldset tag. I created a quick and dirty component (OutlinedBox) to get this effect:
import React from "react";
import {Box, FormLabel} from "#mui/material";
const OutlinedBox = (props) => {
const {
label,
children
} = props;
return (
<Box>
<FormLabel
sx={{
marginLeft: "0.71em",
marginTop: "-0.71em",
paddingLeft: "0.44em",
paddingRight: '0.44em',
zIndex: 2,
backgroundColor: (theme) => theme.palette.background.default,
position: "absolute",
fontSize: "0.75em",
width: 'auto',
}}>{label}</FormLabel>
<Box
sx={{
position: 'relative',
borderRadius: theme => theme.shape.borderRadius + 'px',
fontSize: '0.875rem',
}}
>
<Box
sx={{
padding: (theme) => theme.spacing(1),
display: 'flex',
gap: (theme) => theme.spacing(1),
flexWrap: 'wrap',
overflow: 'auto'
}}
>
{children}
</Box>
<fieldset aria-hidden={"true"} style={{
textAlign: 'left',
position: 'absolute',
bottom: 0,
right: 0,
top: '-5px',
left: 0,
margin: 0,
padding: '0 8px',
pointerEvents: 'none',
borderRadius: 'inherit',
borderStyle: 'solid',
borderWidth: '1px',
overflow: 'hidden',
minWidth: '0%',
borderColor: 'rgba(255, 255, 255, 0.23)',
}}
>
<legend style={{
float: 'unset',
overflow: 'hidden',
display: 'block',
width: 'auto',
padding: 0,
height: '11px',
fontSize: '0.75em',
visibility: 'hidden',
maxWidth: '100%',
'-webkit-transition': 'max-width 100ms cubic-bezier(0.0, 0, 0.2, 1) 50ms',
transition: 'max-width 100ms cubic-bezier(0.0, 0, 0.2, 1) 50ms',
whiteSpace: 'nowrap',
}}><span>{label}</span></legend>
</fieldset>
</Box>
</Box>
);
}
export { OutlinedBox };
// Example usage: <OutlinedBox label="Test">Some content here</OutlinedBox>
I figured I'd post it here in case anyone needs the same thing and comes across this question. All the styling stuff was copied from the styles MUI was using. There may be a better way to read some of this off of the theme, so if anyone decides to use this you may want to tweak it some.

How to style material UI box component to overlay

I'm really new when it comes to styling components and making them look the way I want.
My desired outcome is to have two box components that overlap each other for a nice clean look for displaying user stats and remaining targets for the day.
What I have in mind is:
If anyone can give me some pointers with regards to styling the box component to look like the above image, I would be really greatful.
To start please take a look at MUI Box, which provides a great description to play with the Box component of Material-UI.
Here is an example from the link
<Box
sx={{
width: 300,
height: 300,
backgroundColor: 'primary.dark',
'&:hover': {
backgroundColor: 'primary.main',
opacity: [0.9, 0.8, 0.7],
},
}}
/>
sx is being used for styling the Box component and inside this example we can see that we can change the width, height and background color of the box from the component itself. To something similar to what you had requested I took the liberty of using styled-components to style the Box component as follows:
import * as React from "react";
import Box from "#mui/material/Box";
import styled from "styled-components";
const DataBoxContainer = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
top: 20vh;
position: relative;
`;
const StyledOuterBox = styled(Box)`
border-radius: 20px;
position: absolute;
`;
const StyledInnerBox = styled(Box)`
border-radius: 10px;
position: relative;
bottom: 50px;
`;
const StyledData = styled.p`
color: black;
align-self: flex-start;
position: absolute;
bottom: 30px;
margin-inline-start: 20px;
`;
export default function DataBox() {
return (
<DataBoxContainer>
<StyledOuterBox
sx={{
width: 500,
height: 250,
backgroundColor: "gray"
}}
>
<StyledData>test</StyledData>
</StyledOuterBox>
<StyledInnerBox
sx={{
width: 480,
height: 200,
backgroundColor: "blue"
}}
/>
</DataBoxContainer>
);
}
Feel free to play with this example at CodeSandbox
I'm sure this can be improved but can give you an idea on how to start.
Please feel free to ask me any questions on it, as you requested for pointers but I have provided a code.

Typescript/React: Referring to other styled-components

I am trying to reproduce this code from https://styled-components.com/docs/advanced in typescript.
const Link = styled.a`
display: flex;
align-items: center;
padding: 5px 10px;
background: papayawhip;
color: palevioletred;
`;
const Icon = styled.svg`
flex: none;
transition: fill 0.25s;
width: 48px;
height: 48px;
${Link}:hover & {
fill: rebeccapurple;
}
`;
What do I have to do for it to work in typescript?
The problem was that I was trying to reference a component that I imported from another file instead of that component's styled counterpart. I mistakenly thought it was a typescript issue.

How can I use media query with emotion/styled/macro?

I cannot find any code that using styled macro with media query and don't understand why It's so rare to find code using emotion/styled/macro.
I know it allows css style in object literal
const StyledUl = styled("ul")(
{
backgroundColor: "#fff",
height: "200px",
width: "100%",
overflowY: "scroll",
position: "absolute",
margin: 0,
padding: "5px",
boxShadow: "-1px 15px 34px -21px rgba(0,32,86,0.21)",
boxSizing: "border-box",
borderRadius: "8px",
zIndex: 9999,
}
)
But how can I use media query?
And where can I find documentation about emotion/styled/macro?
Nothing special is required. Just add a #media ... query as a property:
import styled from "#emotion/styled/macro";
const StyledUl = styled("ul")({
"#media (max-width: 600px)": {
backgroundColor: "#000",
color: "#fff"
},
backgroundColor: "#fff",
height: "200px",
width: "calc(100% - 40px)",
overflowY: "scroll",
position: "absolute",
margin: 0,
padding: "5px",
boxShadow: "-1px 15px 34px -21px rgba(0,32,86,0.21)",
boxSizing: "border-box",
borderRadius: "8px",
zIndex: 9999
});
export default StyledUl;
Optionally, you can use a template literal to style a styled.HTMLElement:
import styled from "#emotion/styled/macro";
const StyledUlTemplate = styled.ul`
#media (max-width: 600px) {
background-color: #000;
color: #fff;
}
background-color: #fff;
height: 200px;
width: calc(100% - 40px);
overflow-y: scroll;
position: absolute;
top: 60%;
margin: 0;
padding: 5px;
box-shadow: -1px 15px 34px -21px rgba(0, 32, 86, 0.21);
box-sizing: border-box;
border-radius: 8px;
z-index: 9999;
`;
export default StyledUlTemplate;
Demo (drag the middle bar left/right to resize the Browser tab to trigger the style changes):

Does React Emotion support ::before/ ::after selectors?

I am trying to use React Emotion to set up a horizontal rule with text in the middle. It would look like this:
----------------------SOME TEXT----------------------------------
I found examples on StackOverflow on how to do this with CSS, but it's not working for me.
Here is my DIV that I'm using, but it's not working.
Is this possible to set up with react Emotion? What am I missing?
<div
css={{
display: 'flex',
lineHeight:'1em',
color:'gray',
'&:before, &:after': {
content:'',
display:'inline-block',
flexGrow:'1px',
marginTop:'0.5em',
backgroundColor:'gray',
height:'1px',
marginRight:'10px',
marginLeft:'10px'
}
}}
>
SOME TEXT
</div>
Your code is right about the ::before and ::after syntax,
However, when trying to replicate I found two errors:
The flexGrow shouldn't have a px unit, just 1: flexGrow:'1
The content should have double quotes content:'""'
<div
css={{
display: 'flex',
lineHeight:'1em',
color:'gray',
'&:before, &:after': {
content:'""',
display:'inline-block',
flexGrow:'1',
marginTop:'0.5em',
backgroundColor:'gray',
height:'1px',
marginRight:'10px',
marginLeft:'10px'
}
}}
>
You need pass style object in css function from emotion/css or emotion/react.
You forgot to wrap your styled object in a function from emotion.
If you use an object and not a string, then wrap content in double quotes
// First way, use css from #emotion/css, pass as object
import { css } from '#emotion/css'
<div
className={css({
display: 'flex',
lineHeight: '1em',
color: 'gray',
':before, :after': {
content: '""',
flexGrow: '1',
marginTop: '0.5em',
backgroundColor: 'gray',
height: '1px',
marginRight: '10px',
marginLeft: '10px'
}
})}
>
SOME TEXT
</div>
// Second way, use css from #emotion/css, pass as string
import { css } from '#emotion/css'
<div
className={css`
display: flex;
line-height: 1em;
color: gray;
:before, :after: {
content: '';
flex-grow: 1;
margin-top: 0.5em;
background-color: gray;
height: 1px;
margin-right: 10px;
margin-left: 10px;
}
`}
>
SOME TEXT
</div>
// Third way, use css from #emotion/react
import { css } from '#emotion/react'
<div
css={css`
display: flex;
line-height: 1em;
color: gray;
:before, :after: {
content: '';
flex-grow: 1;
margin-top: 0.5em;
background-color: gray;
height: 1px;
margin-right: 10px;
margin-left: 10px;
}
`}
>
SOME TEXT
</div>
For string interpolation passed for css function you can use it like
let highlight = css`
border: 1px solid grey;
&:after {
position: absolute;
}`;

Resources