All files / src/components/BackToTop BackToTop.tsx

100% Statements 11/11
100% Branches 12/12
100% Functions 3/3
100% Lines 11/11

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86                                        9x 9x           9x 3x       3x 1x       9x                                           2x 2x 2x   2x                                            
import React from 'react';
import Box              from '@mui/material/Box';
import Fab              from '@mui/material/Fab';
import useScrollTrigger from '@mui/material/useScrollTrigger';
import Zoom             from '@mui/material/Zoom';
import { useTheme }     from '@mui/material/styles';
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
import { useTranslation } from 'react-i18next';
 
interface ScrollTopProps {
  /**
   * Optional window ref (pour les iframes etc).
   */
  window?: () => Window;
}
 
/**
 * Ce composant affiche son enfant dans un Zoom quand on scroll (threshold = 100px).
 */
export function ScrollTop(props: ScrollTopProps & { children: React.ReactElement }) {
  const { children, window } = props;
  const trigger = useScrollTrigger({
    target: window ? window() : undefined,
    disableHysteresis: true,
    threshold: 100,
  });
 
  const handleClick = (event: React.MouseEvent<HTMLElement>) => {
    const anchor = (
      (event.currentTarget as HTMLElement).ownerDocument || document
    ).querySelector('#back-to-top-anchor');
 
    if (anchor) {
      anchor.scrollIntoView({ behavior: 'smooth', block: 'center' });
    }
  };
 
  return (
    <Zoom in={trigger}>
      <Box
        onClick={handleClick}
        role="presentation"
        sx={{
          position: 'fixed',
          bottom: 16,
          right: 16,
          zIndex: 1300,
        }}
      >
        {children}
      </Box>
    </Zoom>
  );
}
 
/**
 * Composant à importer dans App.tsx
 */
export default function BackToTop(props: ScrollTopProps) {
  const { t } = useTranslation();
  const theme = useTheme();
  const isDark = theme.palette.mode === 'dark';
 
  return (
    <React.Fragment>
      {/* L'ancre qu'on remontera */}
      <Box id="back-to-top-anchor" />
      <ScrollTop {...props}>
        <Fab
          size="small"
          aria-label={t('scroll.back_to_top')}
          sx={{
            bgcolor: isDark ? 'primary.dark' : 'info.main',
            color: isDark ? 'primary.contrastText' : 'info.contrastText',
            '&:hover': {
              bgcolor: isDark ? 'primary.main' : 'info.light',
            },
          }}
        >
          <KeyboardArrowUpIcon />
        </Fab>
      </ScrollTop>
    </React.Fragment>
  );
}