All files / src/stories IntersectionObserver.stories.tsx

0% Statements 0/23
0% Branches 0/8
0% Functions 0/8
0% Lines 0/22

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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101                                                                                                                                                                                                         
import React, { useState } from 'react';
import { StoryFn } from '@storybook/react';
import { InView } from 'react-intersection-observer';
import { Snackbar, Typography } from '@mui/material';
import Carousel from 'react-multi-carousel';
 
export default {
  title: 'IntersectionObserver',
};
 
type InViewDemoProps = {
  numberOfCarousels: number;
  imagesPerCarousel: number;
};
 
const Template: StoryFn<InViewDemoProps> = (args): JSX.Element => {
  const { numberOfCarousels, imagesPerCarousel } = args;
  const carousels = [...new Array(numberOfCarousels)];
  const [visibleCarousels, setVisibleCarousels] = useState<number[]>([]);
 
  const responsive = {
    // eslint-disable-next-line id-denylist
    any: {
      breakpoint: { max: 10000, min: 0 },
      items: 1,
    },
  };
 
  const setCarouselVisible = (index: number) => {
    if (!visibleCarousels.includes(index)) {
      setVisibleCarousels([...visibleCarousels, index]);
    }
  };
 
  const setCarouselNotVisible = (index: number) => {
    if (visibleCarousels.includes(index)) {
      setVisibleCarousels(visibleCarousels.filter((value: number) => value !== index));
    }
  };
 
  return (
    <>
      <Typography variant={'body1'} sx={{ marginBottom: '100px' }}>
        This story aims to show the NPM package `react-intersection-observer` in action, and shows how you might
        implement it in our React frontend. Use the `InView` component to easily show or hide the contents based on
        whether or not the children are in the browser's viewport. This is especially helpful when rendering very tall
        pages with expensive component hierarchies.
      </Typography>
      <Snackbar open={true}>
        <div>
          <Typography>{`Number of carousels ${numberOfCarousels}.`}</Typography>
          <Typography>{`Number of carousels rendered ${visibleCarousels.length}.`}</Typography>
        </div>
      </Snackbar>
 
      <div>
        {carousels.map((value, index) => (
          <InView key={index}>
            {({ inView, ref }) => {
              const photos = [...new Array(imagesPerCarousel)].map(
                (_value, _index) => `https://source.unsplash.com/random/800x600/?forest,jungle,${_index}`
              );
 
              if (inView) {
                setCarouselVisible(index);
              } else {
                setCarouselNotVisible(index);
              }
 
              return (
                <div ref={ref}>
                  {inView ? (
                    <div style={{ minHeight: '600px' }}>
                      <Carousel responsive={responsive}>
                        {photos.map((p, i) => {
                          return (
                            <div key={`photo-${i}-container`}>
                              <img src={p} alt={p} />
                            </div>
                          );
                        })}
                      </Carousel>
                    </div>
                  ) : null}
                </div>
              );
            }}
          </InView>
        ))}
      </div>
    </>
  );
};
 
export const Default = Template.bind({});
 
Default.args = {
  numberOfCarousels: 10,
  imagesPerCarousel: 3,
};