Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stories bug #200

Open
vasilich6107 opened this issue Apr 17, 2023 · 1 comment
Open

Stories bug #200

vasilich6107 opened this issue Apr 17, 2023 · 1 comment

Comments

@vasilich6107
Copy link

Hi. I tried to implement the stories code from you challenge.
The initial stories implementation has a bug when we mix up the scroll and tap movement through the stories.

Example - tap till the end of the stories, than scroll back with mouse scroll then try to tap forward - nothing works.

i've implemented the solution to improve the gesture mix in react.
If you are accepting PRs I will adapt it to vanilla js code

/* eslint-disable react/style-prop-object */
import { useCallback, useEffect, useRef, useState } from "react";
import "./stories.css";

const storiesBreakpoints = {};

function Stories() {
  const storiesRef = useRef(null);

  const storiesMedian = useCallback(
    () => storiesRef.current.offsetLeft + storiesRef.current.clientWidth / 2,
    [storiesRef]
  );

  const [currentStory, setCurrentStory] = useState(null);

  useEffect(() => {
    for (let i = 0; i < storiesRef.current.children.length; i++) {
      storiesBreakpoints[
        storiesRef.current.children[i].offsetLeft -
          storiesRef.current.offsetLeft
      ] = i;
    }
  }, []);

  useEffect(() => {
    setCurrentStory(storiesRef.current.firstElementChild.lastElementChild);
  }, []);

  const navigateStories = useCallback(
    (direction) => {
      if (currentStory === null) {
        return;
      }

      let lastItemInUserStory;
      let nextUserStory;

      if (direction === "next") {
        lastItemInUserStory = currentStory.parentNode.firstElementChild;
        nextUserStory =
          currentStory.previousElementSibling ||
          currentStory.parentElement.nextElementSibling?.lastElementChild;
      } else if (direction === "prev") {
        lastItemInUserStory = currentStory.parentNode.lastElementChild;

        nextUserStory =
          currentStory.nextElementSibling ||
          currentStory.parentElement.previousElementSibling?.firstElementChild;
      }

      if (lastItemInUserStory === currentStory && nextUserStory) {
        nextUserStory.scrollIntoView({
          behavior: "smooth",
        });
      } else if (nextUserStory) {
        (direction === "prev" ? nextUserStory : currentStory).classList.toggle(
          "seen"
        );
      }

      if (nextUserStory) {
        setCurrentStory(nextUserStory);
      }
    },
    [currentStory]
  );

  const storiesClick = useCallback(
    (e) => {
      if (e.target.nodeName !== "ARTICLE") {
        return;
      }

      navigateStories(e.clientX > storiesMedian() ? "next" : "prev");
    },
    [navigateStories, storiesMedian]
  );

  return (
    <>
      <div
        ref={storiesRef}
        className="stories"
        onClick={storiesClick}
        onScroll={(e) => {
          const currentUserIndex =
            storiesBreakpoints[e.target.scrollLeft] ?? null;

          let currentStory = null;

          if (currentUserIndex != null) {
            const userStories = Array.from(
              storiesRef.current.children[currentUserIndex]?.children
            );

            currentStory =
              userStories.findLast((e) => !e.classList.contains("seen")) ??
              null;
          }

          setCurrentStory(currentStory);
        }}
      >
        <section className="user">
          <article
            className="story story1"
            style={{ "--bg": "url(https://picsum.photos/480/840)" }}
          ></article>
          <article
            className="story story2"
            style={{ "--bg": "url(https://picsum.photos/480/841)" }}
          ></article>
        </section>
        <section className="user">
          <article
            className="story story3"
            style={{ "--bg": "url(https://picsum.photos/481/840)" }}
          ></article>
        </section>
        <section className="user">
          <article
            className="story story4"
            style={{ "--bg": "url(https://picsum.photos/481/841)" }}
          ></article>
        </section>
        <section className="user">
          <article
            className="story story5"
            style={{ "--bg": "url(https://picsum.photos/482/840)" }}
          ></article>
          <article
            className="story story6"
            style={{ "--bg": "url(https://picsum.photos/482/843)" }}
          ></article>
          <article
            className="story story7"
            style={{ "--bg": "url(https://picsum.photos/482/844)" }}
          ></article>
        </section>
      </div>
    </>
  );
}

export default Stories;
@argyleink
Copy link
Owner

nice, yes, the demo does have that issue 👍🏻 I never implemented a scroll observer that tried to determine the current snapped set and then reconciled the index. I see your onScroll handler there that does that work, rad.

i'd love to see a demo of the react component, your implementation looks worth sharing!

and yes, if you want to submit a PR with a vanilla js update that fixes that inconsistency in snapped item and the tap snap index, that'd be grrrreat!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants