npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-horizontal-scrolling-menu-alt

v3.2.9

Published

Scrolling horizontal menu component for React, support mouse and touch devices.

Downloads

255

Readme

React horizontal scrolling menu

Stand With Ukraine

example

npm Tests Codacy Badge Codacy Badge Commitizen friendly npm bundle size (minified + gzip) Donate Bitcoin

Proud corner

performance-dashboard-on-aws | React status code

Examples

Demo

Basic example

Hidden scrollbar and arrows on bottom

Select item

Drag by mouse

Click and select multiple items

Scroll by 1 item

Center items

Dynamically add items when last is visible

apiRef - controling component outside

Add item and scroll to it

RTL

Loop scroll

Custom transition/animation

Previous version V1

This is a horizontal scrolling menu component for React. Menu component has adaptive width, just set width for parent container. Items width will be determined from CSS styles.

For navigation, you can use scrollbar, native touch scroll, mouse wheel or drag by mouse.

Component provide context with visible items and helpers.

Possible set default position on initialization.

:star: if you like the project :)

Quick start

yarn add react-horizontal-scrolling-menu

In project:

import React from 'react';
import { ScrollMenu, VisibilityContext } from 'react-horizontal-scrolling-menu';

const getItems = () =>
  Array(20)
    .fill(0)
    .map((_, ind) => ({ id: `element-${ind}` }));

function App() {
  const [items, setItems] = React.useState(getItems);
  const [selected, setSelected] = React.useState([]);
  const [position, setPosition] = React.useState(0);

  const isItemSelected = (id) => !!selected.find((el) => el === id);

  const handleClick =
    (id) =>
    ({ getItemById, scrollToItem }) => {
      const itemSelected = isItemSelected(id);

      setSelected((currentSelected) =>
        itemSelected
          ? currentSelected.filter((el) => el !== id)
          : currentSelected.concat(id)
      );
    };

  return (
    <ScrollMenu LeftArrow={LeftArrow} RightArrow={RightArrow}>
      {items.map(({ id }) => (
        <Card
          itemId={id} // NOTE: itemId is required for track items
          title={id}
          key={id}
          onClick={handleClick(id)}
          selected={isItemSelected(id)}
        />
      ))}
    </ScrollMenu>
  );
}

function LeftArrow() {
  const { isFirstItemVisible, scrollPrev } =
    React.useContext(VisibilityContext);

  return (
    <Arrow disabled={isFirstItemVisible} onClick={() => scrollPrev()}>
      Left
    </Arrow>
  );
}

function RightArrow() {
  const { isLastItemVisible, scrollNext } = React.useContext(VisibilityContext);

  return (
    <Arrow disabled={isLastItemVisible} onClick={() => scrollNext()}>
      Right
    </Arrow>
  );
}

function Card({ onClick, selected, title, itemId }) {
  const visibility = React.useContext(VisibilityContext);

  return (
    <div
      onClick={() => onClick(visibility)}
      style={{
        width: '160px',
      }}
      tabIndex={0}
    >
      <div className="card">
        <div>{title}</div>
        <div>visible: {JSON.stringify(!!visibility.isItemVisible(itemId))}</div>
        <div>selected: {JSON.stringify(!!selected)}</div>
      </div>
      <div
        style={{
          height: '200px',
        }}
      />
    </div>
  );
}

export default App;

Check out Example in example-nextjs folder for info how to implement more features like mouse drag or disable body scroll.

Example

You can clone repository and run demo project.

git clone https://github.com/asmyshlyaev177/react-horizontal-scrolling-menu
yarn install
yarn run demo

Helpers and api

Children of main ScrollMenu component(arrows, fotter, items) can use VisibilityContext to access state and callbacks. Function callbacks also pass context, eg onWheel, onScroll etc.

Properties and callbacks

| Prop | Signature | | ------------------------ | ------------------------------------------------------------- | | LeftArrow | React component for left arrow | | RightArrow | React component for right arrow | | Header | React component Header | | Footer | React component Footer | | onWheel | (VisibilityContext, event) => void | | onScroll | (VisibilityContext, event) => void, will fire before scroll | | onInit | (VisibilityContext) => void | | apiRef | React.RefObject | | onUpdate | (VisibilityContext) => void | | onMouseDown | (VisibilityContext) => (React.MouseEventHandler) => void | | onMouseUp | (VisibilityContext) => (React.MouseEventHandler) => void | | onMouseMove | (VisibilityContext) => (React.MouseEventHandler) => void | | itemClassName | ClassName of Item | | separatorClassName | ClassName of Item's separator | | scrollContainerClassName | ClassName of scrollContainer | | transitionDuration | Duration of transitions in ms, default 500 | | transitionBehavior | 'smooth' |'auto' | customFunction | | transitionEase | Ease function, eg t => t*(2-t) | | wrapperClassName | ClassName of the outer-most div | | RTL | Enable Right to left direction | | noPolyfill | Don't use polyfill for scroll, no transitions |

VisibilityContext

| Prop | Signature | | --------------------------------------------------------------- | ------------------------------------------------------ | | getItemById | itemId => IOItem | undefined | | getItemElementById | itemId => DOM Element | null | | getItemByIndex | index => IOItem | undefined | | getItemElementByIndex | index => DOM Element | null | | getNextElement (use this first, result without separators) | () => IOItem | undefined | | getNextItem | () => IOItem | undefined) | | getPrevElement (use this first, result without separators) | () => IOItem | undefined | | getPrevItem | () => IOItem | undefined | | initComplete | boolean | | isFirstItemVisible | boolean | | isItemVisible | itemId => boolean | | isLastItem | boolean | | isLastItemVisible | boolean | | scrollNext | (behavior, inline, block, ScrollOptions) => void | | scrollPrev | (behavior, inline, block, ScrollOptions) => void | | scrollToItem | (item, behavior, inline, block, ScrollOptions) => void | | initComplete | boolean | | items | ItemsMap class instance | | scrollContainer | Ref | | visibleElements | ['item1', 'item2'] | | visibleElementsWithSeparators | ['item1', 'item1-separator', 'item2'] | | visibleItemsWithoutSeparators (deprecated, use visibleElements) | ['item1', 'item2'] | | visibleItems (deprecated, use visibleElementsWithSeparators) | ['item1', 'item1-separator', 'item2'] |

Transition/Animation

NOTE: won't work with RTL prop

Can use transitionDuration, transitionEase and transitionBehavior See example

ScrollOptions for scrollToItem, scrollPrev, scrollNext

Will override transition* options passed to ScrollMenu

{
  // target,
  behavior, // 'smooth', 'auto' or custom function
    // inline,
    // block,
    {
      duration: number, // number in milliseconds
      ease: (t) => t, // ease function, more https://gist.github.com/gre/1650294#file-easing-js
    };
}

Other helpers

slidingWindow

Can get previous or next visible group of items with slidingWindow(allItems: string[], visibleItems: string[]) helper, e.g

slidingWindow(allItems, visibleItems)
.prev()
//.next()

getItemsPos

Can get first, center and last items, e.g.

const prevGroup = slidingWindow(allItems, visibleItems).prev()
const { first, center: centerItem, last } = getItemsPos(prevGroup)

// and scroll to center item of previous group of items
scrollToItem(getItemById(centerItem, 'smooth', 'center'))

Check out examples

apiRef

Can pass Ref object to Menu, current value will assigned as VisibilityContext. But visibleItems and some other values can be staled, so better use it only for firing functions like scrollToItem.

For scrolling use apiRef.scrollToItem(apiRef.getItemElementById) instead of apiRef.scrollToItem(apiRef.getItemById).

Can get item outside of context via apiRef.getItemElementById(id) or directly via document.querySelector(`[data-key='${itemId}']`). See apiRef example and Add item and scroll to it

Browser support

  • Browser must support IntersectionObserver API and requestAnimationFrame or use polyfills.
  • Only modern browsers, no IE or smart toasters

About

My first npm project. Sorry for my english.

Any contribution and correction appreciated. Just fork repo, commit and make PR, don't forget about tests.

Contributing

Changelog