I'm trying to make a very simple react component that would crop images with react-easy-crop. Apparently it is possible to customize the style of react-easy-crop module with style prop that takes 3 objects: containerStyle, mediaStyle and cropAreaStyle.
This is the default layout:
I want to expand cropArea to full width of its container and to fit media in it by height (so that we don't see the part of the original image outside of cropArea) but can't figure out how to do it. The cropAreaStyle object doesn't seem to affect width or height since it is calculated and injected in the module file (even after setting disableAutomaticStylesInjection to true).
import React from 'react'
import ReactDOM from 'react-dom'
import Cropper from 'react-easy-crop'
import './styles.css'
class App extends React.Component {
state = {
imageSrc:
'https://img.huffingtonpost.com/asset/5ab4d4ac2000007d06eb2c56.jpeg?cache=sih0jwle4e&ops=1910_1000',
crop: { x: 0, y: 0 },
zoom: 1,
aspect: 1 / 1,
style: { containerStyle: { position: "absolute", top: "0", width: "calc(100% - 2px)", height: window.innerWidth, overflow: "hidden", border: "1px solid black" },
mediaStyle: { height: "100%", display: "block" },
cropAreaStyle: {position: "absolute", top: "0", border: "1px solid black", width: "100%", height: "100%" }}
}
onCropChange = (crop) => {
this.setState({ crop })
}
onCropComplete = (croppedArea, croppedAreaPixels) => {
console.log(croppedArea, croppedAreaPixels)
}
onZoomChange = (zoom) => {
this.setState({ zoom })
}
render() {
return (
<div className="App">
<div className="crop-container">
<Cropper
image={this.state.imageSrc}
crop={this.state.crop}
zoom={this.state.zoom}
aspect={this.state.aspect}
onCropChange={this.onCropChange}
onCropComplete={this.onCropComplete}
onZoomChange={this.onZoomChange}
style={this.state.style}
disableAutomaticStylesInjection={true}
/>
</div>
</div>
)
}
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
This is what I'm trying to achieve:
The black square is cropArea that I can't resize...
I want cropArea to remain square.
Is there an easy way to do this, without changing the module file?
The solution with another module is acceptable also
Thanks in advance
I tried to use the object cropAreaStyle but it's not working, instead use the prop cropSize and don't pass the prop aspect.
In order to get the height of the media pass the prop onMediaLoaded:
onMediaLoad = (mediaSize) => {
this.setState({
cropHeight: mediaSize.height,
});
};
App.js
import React from 'react';
import ReactDOM from 'react-dom';
import Cropper from 'react-easy-crop';
import './style.css';
class App extends React.Component {
state = {
imageSrc:
'https://img.huffingtonpost.com/asset/5ab4d4ac2000007d06eb2c56.jpeg?cache=sih0jwle4e&ops=1910_1000',
crop: { x: 0, y: 0 },
zoom: 1,
cropHeight: 0,
};
onCropChange = (crop) => {
this.setState({ crop });
};
onCropComplete = (croppedArea, croppedAreaPixels) => {
console.log(croppedArea, croppedAreaPixels);
};
onZoomChange = (zoom) => {
this.setState({ zoom });
};
onMediaLoad = (mediaSize) => {
this.setState({
cropHeight: mediaSize.height,
});
};
render() {
const cropSize = {
height: `${this.state.cropHeight}px`,
width: '100%',
};
return (
<div className="App">
<div className="crop-container">
<Cropper
image={this.state.imageSrc}
crop={this.state.crop}
zoom={this.state.zoom}
onCropChange={this.onCropChange}
onCropComplete={this.onCropComplete}
onZoomChange={this.onZoomChange}
onMediaLoaded={this.onMediaLoad}
cropSize={cropSize}
/>
</div>
</div>
);
}
}
export default App;
Demo: https://stackblitz.com/edit/react-4zmgud
It seems that what you need is the objectFit property set to vertical-cover.
See this demo: https://codesandbox.io/s/crazy-liskov-04u7m0
Related
How can I mock next/future/image component from NextJS in Storybook?
Mock with support of fill property from v12.2.4
// .storybook/preview.js
import * as NextFutureImage from "next/future/image";
Object.defineProperty(NextFutureImage, "default", {
configurable: true,
value: (props) => {
const { fill, style, ...restProps } = props;
return (
<img
{...restProps}
style={
fill
? {
position: "absolute",
height: "100%",
width: "100%",
inset: 0,
...style
}
: style
}
/>
);
},
});
I am using Material UI v5, and am trying to make a responsive drawer where for smaller devices it will take up 100% of screen width while for larger devices it should only take 1/3 of screen width. But I have no idea how to access Paper property to modify the actual width and make it responsive.
My code:
import { Drawer, styled } from "#mui/material";
const ResponsiveDrawer = styled(Drawer)(({ theme }) => ({
[theme.breakpoints.up("md")]: {
width: "33%", // THIS ONLY CHANGES DRAWER WIDTH NOT PAPER WIDTH INSIDE THE DRAWER
},
[theme.breakpoints.down("md")]: {
width: "100%",
},
}));
export { ResponsiveDrawer };
How I use it:
import { ResponsiveDrawer } from "./Style";
<ResponsiveDrawer
anchor="right"
open={drawer.state}
onClose={() => drawer.onClick(false)}
>
...
</ResponsiveDrawer>
I figured it out shortly after posting the question. This involves inline styling using useMediaQuery.
const largeScreen = useMediaQuery(theme.breakpoints.up("sm"))
<Drawer
anchor="right"
open={drawer.state}
onClose={() => drawer.onClick(false)}
PaperProps={largeScreen ? {
sx: {
width: 450,
}
} : {
sx: {
width: "100%",
}
}
}
>
<CartContent cart={cart} drawer={drawer}/>
</Drawer>
You can add a div inside the <Drawer> or <SwipeableDrawer> component like so and control the width of the div through CSS (or emotion/styled, if you prefer).
<Drawer ...>
<div className="container">...</div>
</Drawer>
.container {
width: 95vw; // for mobile
... add media queries for rest of the screen sizes here
}
In their docs (expand the code blow) they give an example how to access the paper CSS, where you could add your width settings:
const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open' })(
({ theme, open }) => ({
width: drawerWidth,
flexShrink: 0,
whiteSpace: 'nowrap',
boxSizing: 'border-box',
...(open && {
...openedMixin(theme),
'& .MuiDrawer-paper': openedMixin(theme),
}),
...(!open && {
...closedMixin(theme),
'& .MuiDrawer-paper': closedMixin(theme),
}),
}),
);
They add the same mixin to '& .MuiDrawer-paper' in the main drawer css.
So for your responsive drawer you should add this paper selector to your styled CSS (maybe check with the inspector, if its the right one):
const ResponsiveDrawer = styled(Drawer)(({ theme }) => ({
[theme.breakpoints.up("md")]: {
width: "33%",
'& .MuiDrawer-paper': {
width: "33%",
},
},
[theme.breakpoints.down("md")]: {
width: "100%",
'& .MuiDrawer-paper': {
width: "100%",
},
},
}));
More information about customizing nested elements can be found on https://mui.com/material-ui/customization/how-to-customize/#the-sx-prop.
Suppose I have a modal in react-native view and whenever I open the modal I want to blurr or change color of background view just focused on modal only.
Thanks in advance
Use react-native-blur
import React, { Component } from "react";
import { Animated, View, Platform, Easing, StyleSheet} from "react-native";
import { BlurView } from "#react-native-community/blur";
export default class Blur extends Component {
render() {
return (
<BlurView
style={styles.blur}
blurType="light"
blurAmount={10}
reducedTransparencyFallbackColor="white"
/>
);
}
}
const styles = StyleSheet.create({
blur: {
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0,
justifyContent: "center",
backgroundColor: "rgba(100,100,100, 0.5)",
padding: 20,
// zIndex: 10,
// opacity: 0.5,
},
});
I use a universal blur HOC, that fixes some iOS\Android bugs
import React from 'react';
import { Button, Text, View } from 'react-native';
import { withBlurModal } from './MyWithBlurModal';
const MyModalContent = ({ openModal, closeModal }) => (
<View>
<Text>MyModalContent</Text>
<Button title="Close modal" onPress={closeModal} />
</View>
);
const MyScreen = ({ openModal, closeModal, blurTargetRef }) => (
<View
// ref need for Android to indicate what part of View need to blur
ref={blurTargetRef}
>
<Button title="Open modal" onPress={openModal} />
</View>
);
const Screen = withBlurModal(MyModalContent)(MyScreen);
I've got a problem I can't seem to solve.
I use a component several times in my app but I'd like the background to be different.
I've declared an empty state for the moment, which I'm using in background-color but I can't define the color the component will have. How can I do this?
Thanks for your help
Here is a little piece of my code :
class Gallery extends React.Component {
constructor(props) {
super(props)
this.state = {
activeGal: [],
width: 1920,
teamGal: {},
isOpen: false,
photoIndex: 0,
bgColor: ''
}
}
render() {
const {activeGal, width, teamGal, isOpen, photoIndex, bgColor} = this.state
.gallery {
background-color: ${bgColor};
padding-bottom: 55px;
}
The easiest (and not recommended) way is to use the style prop:
class Gallery extends React.Component {
render() {
const { backgroundColor } = this.props;
return <div style={{ width: "100%", height: "100%", backgroundColor }} />;
}
}
const App = () => {
return (
<div style={{ height: "50vh", width: "50vw" }}>
<Gallery backgroundColor="blue" />
</div>
);
};
More popular solutions are using CSS-in-JS (like styled-components) or CSS variables (See CSS Variables for React Devs).
I have a separate App.css file that has global css attributes and have classes for responsiveness. The issue is I want to render elements differently for separate devices but can't seem to figure out how to do that as using conditionals isn't applying as such.
import UserItem from "./UserItem";
import Spinner from "../layout/Spinner";
import PropTypes from "prop-types";
const Users = ({ users, loading }) => {
if (loading) {
return <Spinner />;
} else {
return (
<div style={userStyle} className='body'>
{users.map((user) => {
return <UserItem key={user.id} user={user} />;
})}
</div>
);
}
};
const windowWidth = window.innerWidth;
Users.propTypes = {
users: PropTypes.array.isRequired,
loading: PropTypes.bool.isRequired,
};
const userStyle = {
display: "grid",
gridTemplateColumns: "repeat(3, 1fr)",
gridGap: "1rem",
};
export default Users;
My css #media query which I am trying to apply to effect change on a small device.
/* Mobile Styles */
#media (max-width: 700px) {
.hide-sm {
display: none;
}
}
How do I implement this #media css style so that it can render the page differents through jsx?
You can use material ui. that will fulfil your requirement. Please check this example:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Typography from '#material-ui/core/Typography';
import { green } from '#material-ui/core/colors';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(1),
[theme.breakpoints.down('sm')]: {
backgroundColor: theme.palette.secondary.main,
},
[theme.breakpoints.up('md')]: {
backgroundColor: theme.palette.primary.main,
},
[theme.breakpoints.up('lg')]: {
backgroundColor: green[500],
},
},
}));
export default function MediaQuery() {
const classes = useStyles();
return (
<div className={classes.root}>
<Typography variant="subtitle1">{'down(sm): red'}</Typography>
<Typography variant="subtitle1">{'up(md): blue'}</Typography>
<Typography variant="subtitle1">{'up(lg): green'}</Typography>
</div>
);
}
Material UI
You can use following example too.
class Card extends Component {
constructor() {
super();
this.mediaQuery = {
desktop: 1200,
tablet: 768,
phone: 576,
};
this.state = {
windowWidth: null
};
}
componentDidMount() {
window.addEventListener('resize', () => {
this.setState({windowWidth: document.body.clientWidth})
});
}
render() {
return (
<div style={{
width: this.state.windowWidth > this.mediaQuery.phone
? '50%'
: '100%',
//more styling :)
}}>
<!-- <Card> contents -->
</div>
);
}
}
Source
I suggest that use CSS #media query to make responsive layouts.
But if you insist on implement with JS and React you should get windowWidth after component mounted. You can use useEffect hook to do so and save value in a state:
const [windowWidth, setWindowWidth] = useState('');
useEffect(() => {
setWindowWidth(window.innerWidth) // or better one -> window.clientWidth
});