When i change orientation on tablet the slider breaks (shows 1 broken slide). Expected behavior ( 2 slides 50% width in portrait orientation). I try to fix with ref.current.swiper.update(), but it don't work
const ref = useRef()
const handleResize = () => {
ref?.current.swiper.update()
}
useEventListener('resize', handleResize)
<Swiper
loop
watchOverflow
ref={ref}
className="apartment-swiper"
breakpoints={{
768: {
slidesPerView: 'auto',
},
1280: {
slidesPerView: 1,
},
}}
>
{photo?.map((item, index) => (
<SwiperSlide className="swiper-slide" key={index}>
<img className="swiper-slide" src={item.url} alt="slide" />
</SwiperSlide>
))}
</Swiper>
try to add the parameters updateOnWindowResize or observer properties
<Swiper
loop
watchOverflow
observer={'true'}
className="apartment-swiper"
breakpoints={{
768: {
slidesPerView: 'auto',
},
1280: {
slidesPerView: 1,
},
}}
>
{photo?.map((item, index) => (
<SwiperSlide className="swiper-slide" key={index}>
<img className="swiper-slide" src={item.url} alt="slide" />
</SwiperSlide>
))}
</Swiper>
This problem - swiperRef1.current.swiper.autoplay.timeout = 366 by def!:)
To do:
console.log(swiperRef1.current.swiper)
swiperRef1.current.swiper.autoplay.timeout = 3;
console.log(swiperRef1.current.swiper.autoplay.timeout)
Related
Trying to use tabs as links but I can't find any where that explains how to do it when you are styling a tab component. I get the syntax that if you use a Tab component you should do this:
<Tab value="..." component={Link} to="/" >
However if I have styled the Tab before and created an additional component like below, I can't find anything. I did this because I couldn't style the tab directly and I found this solution.
//Styled Tab
const StyledButton = styled(Button)(() => ({
...theme.typography.estimateBtn,
borderRadius: "50px",
marginLeft: "25px",
marginRight: "25px",
height: "50px",
}));
// nav container
const ToolBarCom: React.FC = () => {
const [value, setValue] = React.useState(0);
// handles classes for non react elements
const classes = useStyles();
const onChangeHandler = (e: React.SyntheticEvent, value: number) => {
setValue(value);
};
return (
<ToolBar disableGutters>
{/* <Typography variant='h3'>Arc Development</Typography> */}
<img src={logo} alt='company logo' className={classes.logo} />
<Tabs
value={value}
onChange={onChangeHandler}
textColor='secondary'
indicatorColor='primary'
className={classes.tabsContainer}
variant='scrollable'
scrollButtons='auto'>
<StyledTab value={0} label='Home' />
<StyledTab value={1} label='Services' />
<StyledTab value={2} label=' The Revolution' />
<StyledTab value={3} label='About Us' />
<StyledTab value={4} label=' Contact Us' />
</Tabs>
<StyledButton variant='contained' color='secondary'>
Free Trial
</StyledButton>
</ToolBar>
);
I had to restyle the Tab with useStyle hook. You have to find the root of the tab component. I couldn't find any documentation for the issue above. See below:
const useStyles = makeStyles(() => ({
logo: {
height: "5em",
},
tabsContainer: {
marginLeft: "auto",
color: "white",
},
tab: {
"&.MuiTab-root": {
...theme.typography.tab,
minWidth: 10,
marginLeft: "25px",
},
},
}));
When I delete products from my cart, the last product <CartComponent /> which I want to delete doesn't animate. I use framer-motion to this project and next.js/chakra-ui/redux.
I followed the docs on framer motion with animate-presence:
Multiple children AnimatePresence works the same way with multiple
children. Just ensure that each has a unique key and components will
animate in and out as they're added or removed from the tree.
I recorded a video on youtube to show the problem more clearly:
youtube video showing the problem
Here's cart page below:
// some imports up here :D /\
const MotionBox = motion<BoxProps>(Box);
const Cart = () => {
const selectProducts = useSelector(selectAllDataFromStore);
const dispatch = useDispatch();
return (
<>
<PageLayout title='Koszyk' description='Fake Sugar - koszyk'>
<VStack>
{selectProducts.length > 0 ? (
<Box>
<AnimatePresence>
{selectProducts.map((item) => {
return (
<MotionBox
animate={{ opacity: 1 }}
exit={{ opacity: 0, x: -200 }}
key={item.slug}
>
<CartComponent item={item} />
</MotionBox>
);
})}
</AnimatePresence>
<Box pt={4}>
<Center>
<Divider orientation='horizontal' />
</Center>
<Button mt={2} onClick={() => dispatch(clearCart())}>
Wyczyść koszyk
</Button>
</Box>
</Box>
) : (
<MotionBox
initial={{ opacity: 0, y: -400 }}
animate={{ opacity: 1, y: 0, transition: { duration: 2 } }}
zIndex='tooltip'
>
<Flex direction='column' align='center' justify='center'>
<Heading as='h3' fontSize='3xl'>
Twój koszyk jest pusty.
</Heading>
<NextLink href='/' passHref>
<Button colorScheme='gray'>Przeglądaj produkty</Button>
</NextLink>
</Flex>
</MotionBox>
)}
</VStack>
</PageLayout>
</>
);
};
export default Cart;
edit 1: I didnt mention that before I wrap it with ternary operator, it was animating the last component when I delete it. So everything was good!
so it was like
youtube video: before it worked it was like
const Cart = () => {
const selectProducts = useSelector(selectAllDataFromStore);
const dispatch = useDispatch();
return (
<>
<PageLayout title='Koszyk' description='Fake Sugar - koszyk'>
<VStack>
<Box>
<AnimatePresence>
{selectProducts.map((item) => {
return (
<MotionBox
animate={{ opacity: 1 }}
exit={{ opacity: 0, x: -200 }}
key={item.slug}
>
<CartComponent item={item} />
</MotionBox>
);
})}
</AnimatePresence>
</Box>
</VStack>
</PageLayout>
</>
);
};
export default Cart;
hmm sussy!
I have a swiper.js slider made in react. If I have 8 images in the swiper and then I navigate to the 8th thumbnail and click on the 7th thumb it will slider the thumbnail part up. Is there a way to prevent this behavior from happening?
What I want to do is for it to only auto slide if there are more slides up or down available. For example, if I have 5 thumbnails and slide [2, 3, 4, 5, 6] are visible, if I select slide 6 it would move over and show slide 7 available and if I select slide 2 it would slide over and show slide 1. That is the only movement I want it to do. Is that feature available in the docs?
<div className="mainSliderWrap">
<Swiper
pagination
onSlideChange={swiper => {
setImageSelectedIndex(swiper.activeIndex + 1)
return true
}}
thumbs={{ swiper: thumbsSwiper }}>
{products.images.map((product, index) => (
<SwiperSlide key={product.originalSrc}>
<img
className={classes.mainSliderImg}
ref={el => {
imagesRef.current[index] = el as HTMLImageElement
}}
src={product.originalSrc}
data-zoom={product.originalSrc}
alt={product.title}
height={360}
width={360}
/>
</SwiperSlide>
))}
</Swiper>
</div>
<div
className={[
"productSlider",
ProductSliderOrientation(width) === "horizontal" &&
"horizontalProductSlider"
].join(" ")}>
<div className="swiper-button-next mainProdNext" />
<div className="swiper-button-prev mainProdPrev" />
<Swiper
direction={ProductSliderOrientation(width)}
touchRatio={1}
threshold={10}
slidesPerView={slidesPerView}
spaceBetween={15}
navigation={{
nextEl: ".mainProdNext",
prevEl: ".mainProdPrev"
}}
onSwiper={setThumbsSwiper}
breakpoints={{
0: {
spaceBetween: 10,
slidesOffsetBefore: 20,
slidesOffsetAfter: 20
},
576: {
spaceBetween: 10,
slidesPerView: 5
},
768: {
touchRatio: 0,
slidesPerView: 5
},
992: {
touchRatio: 1,
slidesPerView: 5
},
1200: {
touchRatio: 0,
slidesPerView: 5
}
}}>
{products &&
products.images.map(product => (
<SwiperSlide key={product.originalSrc}>
<ProductImage
image={product}
alt={products.title}
moduleClass={classes.productImagePick}
gatsbyImageClass={classes.productImagePickGatsby}
/>
</SwiperSlide>
))}
</Swiper>
</div>
</div>
</div>
It looks like there is no way to implement thumbnails with this behavior without manipulating data. So idea is when you change a thumbnail you need to reorder data in order to show next/previous thumb.
export default function App() {
const [thumbsSwiper, setThumbsSwiper] = useState(null);
const [data, setData] = useState([
"https://swiperjs.com/demos/images/nature-1.jpg",
"https://swiperjs.com/demos/images/nature-2.jpg",
"https://swiperjs.com/demos/images/nature-3.jpg",
"https://swiperjs.com/demos/images/nature-4.jpg",
"https://swiperjs.com/demos/images/nature-5.jpg",
"https://swiperjs.com/demos/images/nature-6.jpg",
"https://swiperjs.com/demos/images/nature-7.jpg",
"https://swiperjs.com/demos/images/nature-8.jpg",
"https://swiperjs.com/demos/images/nature-9.jpg",
"https://swiperjs.com/demos/images/nature-10.jpg"
]);
return (
<>
<Swiper
style={{
"--swiper-navigation-color": "#fff",
"--swiper-pagination-color": "#fff"
}}
loop={false}
spaceBetween={10}
navigation={true}
thumbs={{ swiper: thumbsSwiper }}
className="mySwiper2"
onSlideChange={(e) => {
if (e.realIndex % 3 === 0) {
// move first element to the end
const newData = [...data];
newData.push(newData.shift());
setData(newData);
e.slideTo(e.realIndex - 1);
}
if (e.realIndex === 0) {
// move last element to the beginning
const newData = [...data];
newData.unshift(newData.pop());
setData(newData);
e.slideTo(e.realIndex + 1);
}
}}
>
{data.map((img) => (
<SwiperSlide key={img}>
<img src={img} />
</SwiperSlide>
))}
</Swiper>
<Swiper
onSwiper={setThumbsSwiper}
loop={false}
loopedSlides={1}
spaceBetween={10}
slidesPerView={4}
freeMode={false}
watchSlidesVisibility={true}
watchSlidesProgress={true}
className="mySwiper"
>
{data.map((img) => (
<SwiperSlide key={img}>
<img src={img} />
</SwiperSlide>
))}
</Swiper>
</>
);
}
Here is a codesandbox
This is a quick example only. I hope it will help you.
I have a tab component in Material-UI and I want to implement a tooltip on it.
My problem is that when I click the tab component, the tooltip is not disappearing. It must disappear after I click on that tab.
Currently, it continues to be visible even after I click on the tab.
How do I rectify that?
<Tabs
className="navbar-routes"
value={value}
style={{ color: 'green'}}
indicatorColor="secondary"
onChange={handleChange}
>
{
tabsData.map(({id,title,description}) => {
return(
<ToolTip description={description}>
<Tab
style={{
minWidth: 10,
fontSize: '80%',
fontWeight: 'bold',
marginLeft: '-4px',
marginRight: 4
}}
key={id}
component={Link}
to={`/${title}`}
label={`${title}`}
/>
</ToolTip>
);
}
)}
</Tabs>
If you look at the document of Material-UI tooltip API
You would find a props named disableHoverListener
bool
default: false
Do not respond to hover events.
Set it as True would turn off the tooltip onMouseOver event trigger.
Update
Or you can simply make it totally under control.
By binding the onClick, onMouseOver, onMouseLeave, open to related component.
import React, { useState } from "react";
import "./styles.css";
import { Tooltip, Tab } from "#material-ui/core";
export default function App() {
const [flg, setFlg] = useState(false);
const [isHover, setIsHover] = useState(false);
return (
<div className="App">
<Tooltip
title={"message"}
aria-label="add"
placement="bottom"
open={!flg && isHover}
>
<Tab
label={`Click: ${!flg ? "enabled" : "disabled"}`}
onClick={() => setFlg(!flg)}
onMouseOver={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
/>
</Tooltip>
</div>
);
}
Try it online:
You can also implement a generic tooltip with a managed state when to open/close the tooltip.
import Tooltip, { TooltipProps } from "#mui/material/Tooltip";
import { useState } from "react";
/**
* MUI Tooltip wrapper with adaption to the move away once focuses left.
*/
export function ManagedTooltip(props: TooltipProps) {
const [open, setOpen] = useState<boolean>(false);
// Wrap Tooltip with div to capture mouse events
return <div style={{ display: 'flex' }}
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
onClick={() => setOpen(false)}
>
{/* Show the original MUI Tooltip with all props. */}
{/* Just override the open attribute to be fully managed, and disable internal listeners */}
<Tooltip {...props} open={open} disableHoverListener disableFocusListener />
</div>;
}
Once it's ready, you can use it anywhere exactly like the original MUI tooltip.
<Tabs
className="navbar-routes"
value={value}
style={{ color: 'green'}}
indicatorColor="secondary"
onChange={handleChange}
>
{
tabsData.map(({id,title,description}) => {
return(
<ManagedTooltip description={description}>
<Tab
style={{
minWidth: 10,
fontSize: '80%',
fontWeight: 'bold',
marginLeft: '-4px',
marginRight: 4
}}
key={id}
component={Link}
to={`/${title}`}
label={`${title}`}
/>
</ManagedTooltip>
);
}
)}
</Tabs>
The way I solved this was by rendering the tooltip conditionally. In your case I suppose you want the tooltip not to render for the tab of the current active route:
function ConditionalTooltip({renderTooltip, children, ...props}) {
return renderTooltip ? <Tooltip {...props}>{children}</Tooltip> : children;
}
function Tabs() {
const location = useLocation();
return (
<Tabs
className="navbar-routes"
value={value}
style={{ color: 'green'}}
indicatorColor="secondary"
onChange={handleChange}
>
{
tabsData.map(({id,title,description}) => {
return(
<ConditionalTooltip
renderTooltip={location.pathname.indexOf(title) === -1} /* only render tooltip on not active urls */
title={description}
>
<Tab
style={{
minWidth: 10,
fontSize: '80%',
fontWeight: 'bold',
marginLeft: '-4px',
marginRight: 4
}}
key={id}
component={Link}
to={`/${title}`}
label={`${title}`}
/>
</ConditionalTooltip>
);
}
)}
</Tabs>
)
}
currently I am working on a project with React and Material UI. I want to hover on tabs that will open an menu, but this doesn't really work. I am hoping that you guys can help me (and maybe tell me if I'm approaching this correctly)
Where my tabs are basing of: https://imgur.com/a/HeiL2xo
My current project: https://imgur.com/a/Ik5NEkF
AppBarTop class
class AppBarTop extends Component {
state = {
value: 0,
open: false,
anchorEl: null
};
handleMenuClick = (index) => {
}
handleMenuOpen = (index, event) => {
const {currentTarget} = event;
this.setState({
open: !this.state.open,
anchorEl: currentTarget,
value: index
})
};
handleMenuClose = () => {
this.setState({
open: false,
anchorEl: null,
})
}
handleInputSearch = () => {
};
render() {
const {classes} = this.props;
const {anchorEl, open} = this.state;
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<img src={buddies} alt={"buddies"} height={50} width={50}/>
<div className={classes.grow}/>
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon/>
</div>
<InputBase
placeholder="Search…"
onChange={this.handleInputSearch}
classes={{
root: classes.inputRoot,
input: classes.inputInput
}}
/>
</div>
<div className={classes.grow}/>
<List>
{TopMenu.map((item, index) => (
<Tab key={index} component={Link} to={{pathname: item.pathname}}
classes={{root: classes.tabItem}} label={item.label}/>
))}
</List>
</Toolbar>
<Paper className={classes.grow}>
<Tabs
value={this.state.value}
indicatorColor="primary"
textColor="primary"
centered>
{BottomMenu.map((item, index) => (
<Tab
key={index}
onMouseOver={this.handleMenuOpen.bind(this, index)}
data-key={index}
classes={{root: classes.tabItem}}
label={item.label}
aria-owns={open ? 'menu-list-grow' : undefined}
aria-haspopup={"true"}/>
))}
</Tabs>
<Popper open={open} anchorEl={anchorEl} id="menu-list-grow">
<Paper>
<MenuList>
{BottomMenu[this.state.value].items.map((item, index) => (
<MenuItem key={index} onClick={this.handleMenuClose}>{item}</MenuItem>
))}
</MenuList>
</Paper>
</Popper>
</Paper>
</AppBar>
</div>
);
}
}
export default withStyles(styles)(AppBarTop)
The key problem here is that the onMouseOver event handler is fired multiple times as you move around the <Tab> component. Your handleMenuOpen function is not built to handle this.
I've replicated your issue in a CodeSandbox here: https://codesandbox.io/s/qkw8rr4mk4
The following 3 points will fix your menu issues:
Change handleMenuOpen to be functional by explicitly setting open: true
Use onMouseEnter rather than onMouseOver. This is not required but it makes for more predictable functionality as onMouseEnter is only called once
To automatically close your menu when your mouse leaves them add the onMouseLeave={this.handleMenuClose.bind(this)} property to your parent <div> component
A CodeSandbox with the above 3 points implemented can be found at: https://codesandbox.io/s/6x9w9m6n7r