Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
react-horizontal-scrolling-menu
Advanced tools
Scrolling horizontal menu component for React, support mouse and touch devices.
Add a ⭐️ and follow me to support the project!
performance-dashboard-on-aws | React status code
Dynamically add items when last is visible
apiRef - controling component outside
Swipe on mobile devices(need to run locally, codesandbox has issues)
This is a highly customizable horizontal scrolling menu component for React. Can also use it for Amazon like items block or a Gallery. Menu component is responsive, 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.
Check out examples on Storybook or codesandbox.
:star: if you like the project :)
Cannot use import statement outside a module
npm install --save react-horizontal-scrolling-menu@7.1.1 // last version has a bug
test In project:
import React from 'react';
import { ScrollMenu, VisibilityContext } from 'react-horizontal-scrolling-menu';
import 'react-horizontal-scrolling-menu/dist/styles.css';
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 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>
);
}
const LeftArrow = () => {
const visibility = React.useContext < publicApiType > VisibilityContext;
const isFirstItemVisible = visibility.useIsVisible('first', true);
return (
<Arrow
disabled={isFirstItemVisible}
onClick={() => visibility.scrollPrev()}
className="left"
>
Left
</Arrow>
);
};
const RightArrow = () => {
const visibility = React.useContext < publicApiType > VisibilityContext;
const isLastItemVisible = visibility.useIsVisible('last', false);
return (
<Arrow
disabled={isLastItemVisible}
onClick={() => visibility.scrollNext()}
className="right"
>
Right
</Arrow>
);
};
function Card({ onClick, selected, title, itemId }) {
const visibility = React.useContext < publicApiType > VisibilityContext;
const visible = visibility.useIsVisible(itemId, true);
return (
<div
onClick={() => onClick(visibility)}
style={{
width: '160px',
}}
tabIndex={0}
>
<div className="card">
<div>{title}</div>
<div>visible: {JSON.stringify(visible)}</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.
You can clone repository and run demo project.
git clone https://github.com/asmyshlyaev177/react-horizontal-scrolling-menu
npm run setup
npm run demo
Can clone repo and run storybook
git clone https://github.com/asmyshlyaev177/react-horizontal-scrolling-menu
npm run setup
npm run storybook
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.
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 | React.RefCallback |
options | options for IntersectionObserver - rootMargin , threshold , and ratio to consider element visible |
containerRef | React.RefObject | React.RefCallback |
onUpdate | (VisibilityContext) => void |
onMouseDown | (VisibilityContext) => (React.MouseEventHandler) => void |
onMouseLeave | (VisibilityContext) => (React.MouseEventHandler) => void |
onMouseUp | (VisibilityContext) => (React.MouseEventHandler) => void |
onMouseMove | (VisibilityContext) => (React.MouseEventHandler) => void |
onTouchMove | (VisibilityContext) => (React.TouchEventHandler) => void |
onTouchStart | (VisibilityContext) => (React.TouchEventHandler) => void |
onTouchEnd | (VisibilityContext) => (React.TouchEventHandler) => void |
itemClassName | ClassName of Item |
scrollContainerClassName | ClassName of scrollContainer |
transitionDuration | Duration of transitions in ms, default 500 |
transitionBehavior | 'smooth' |'auto' | customFunction |
wrapperClassName | ClassName of the outer-most div |
RTL | Enable Right to left direction |
noPolyfill | Don't use polyfill for scroll, no transitions, true by default |
Prop | Signature |
---|---|
useIsVisible | (itemId: string, defaultValue?: false) => boolean |
getItemById | itemId => IOItem | undefined |
getItemElementById | itemId => DOM Element | null |
getItemByIndex | index => IOItem | undefined |
getItemElementByIndex | index => DOM Element | null |
getNextElement | () => IOItem | undefined |
getPrevElement | () => IOItem | undefined |
isFirstItemVisible | boolean |
isItemVisible | itemId => boolean |
isLastItem | boolean |
isLastItemVisible | boolean |
menuVisible | { current: boolean } |
scrollNext | (behavior, inline, block, ScrollOptions) => void |
scrollPrev | (behavior, inline, block, ScrollOptions) => void |
scrollToItem | (item, behavior, inline, block, ScrollOptions) => void |
items | ItemsMap class instance |
scrollContainer | Ref |
ItemsMap class store info about all items and has methods to get currently visible items, prev/next item. Also, can subscribe to updates.
Prop/method | Description |
---|---|
subscribe | subscribe for events for itemId or first , last , onInit , onUpdate , eg. items.subscribe('item5', (item) => setVisible(item.visible)) |
unsubscribe | use in useEffect to cleanup, pass same cb instance |
getVisible | return only visible items |
toItems | return ids for all items |
toArr | return all items |
first | return first item |
last | return last item |
prev | (itemId | Item) => previous item | undefined |
next | (itemId | Item) => next item | undefined |
NOTE: won't work with RTL prop
Can use transitionDuration
, and transitionBehavior
See example
Will override transition* options passed to ScrollMenu
{
// target,
behavior, // 'smooth', 'auto' or custom function
// inline,
// block,
{
duration: number, // number in milliseconds
};
}
Can get previous or next visible group of items with slidingWindow(allItems: string[], visibleItems: string[])
helper, e.g
slidingWindow(allItems, visibleItems)
.prev()
//.next()
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
Can pass Ref object to Menu, current value will assigned as VisibilityContext. But 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
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.
FAQs
Scrolling horizontal menu component for React, support mouse and touch devices.
We found that react-horizontal-scrolling-menu demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.