0.0.3 • Published 4 years ago

react-horizontal-scroll-menu v0.0.3

Weekly downloads
88
License
ISC
Repository
github
Last release
4 years ago

React horizontal scroll menu

example

This is horizontal scrolling menu component for React. Menu component has adaptive width, just set width for parent container. Items width will be determinated from css styles. Note: don't set margin for item wrapper, use padding instead. Can use margin for item element those you pass as props.

For navigation you can use arrows, mouse wheel or just drag items.

Component return items position, selected item and click event from callbacks.

Possible set default position and selected item on initialization.

Add star if you like project :)

Quick start

npm install --save react-horizontal-scroll-menu

In project:

import React, { Component } from 'react';
import ScrollMenu from 'react-horizontal-scroll-menu';
import './App.css';

// list of items
const list = [
  { name: 'item1' },
  { name: 'item2' },
  { name: 'item3' },
  { name: 'item4' },
  { name: 'item5' },
  { name: 'item6' },
  { name: 'item7' },
  { name: 'item8' },
  { name: 'item9' }
];

// One item component
// selected prop will be passed
const MenuItem = ({text, selected}) => {
  return <div
    className={`menu-item ${selected ? 'active' : ''}`}
    >{text}</div>;
};

// All items component
// Important! add unique key
export const Menu = (list, selected) =>
  list.map(el => {
    const {name} = el;

    return <MenuItem text={name} key={name} selected={selected} />;
  });


const Arrow = ({ text, className }) => {
  return (
    <div
      className={className}
    >{text}</div>
  );
};


const ArrowLeft = Arrow({ text: '<', className: 'arrow-prev' });
const ArrowRight = Arrow({ text: '>', className: 'arrow-next' });

const selected = 'item1';

class App extends Component {
  constructor(props) {
    super(props);
    // call it again if items count changes
    this.menuItems = Menu(list, selected);
  }

  state = {
    selected
  };

  onSelect = key => {
    this.setState({ selected: key });
  }


  render() {
    const { selected } = this.state;
    // Create menu from items
    const menu = this.menuItems;

    return (
      <div className="App">
        <ScrollMenu
          data={menu}
          arrowLeft={ArrowLeft}
          arrowRight={ArrowRight}
          selected={selected}
          onSelect={this.onSelect}
        />
      </div>
    );
  }
}

In App.css

.menu-item {
  padding: 0 40px;
  margin: 5px 10px;
  user-select: none;
  cursor: pointer;
  border: none;
}
.menu-item-wrapper.active {
  border: 1px blue solid;
}
.menu-item.active {
  border: 1px green solid;
}

.scroll-menu-arrow {
  padding: 20px;
  cursor: pointer;
}

Example

You can clone repository and run demo project from examples folder.

git clone https://github.com/kucukharf/react-horizontal-scroll-menu
cd react-horizontal-scroll-menu/examples
npm install
npm run start

Properties and callbacks

PropsTypeDescriptionRequiredDefault Value
alignCenterBooleanTry to align items by centerfalsetrue
alignOnResizeBooleanTry to align items after resize windowfalsetrue
clickWhenDragBooleanAfter drag end select item under cursor( if any)falsefalse
draggingBooleanAllow drag items by mouse(and touch)falsetrue
wheelBooleanScroll with mouse wheelfalsetrue
arrowLeftReact componentReact component for left arrowfalsenull
dataArray of react componentsMenu items, if empy render null (note, component must have unique key!)true[]
hideArrowsBooleanhide arrows if items fit to one screen, (add class scroll-menu-arrow--disabled to arrows)falsefalse
arrowDisabledClassStringThe class name to append when arrows are disabledfalse"scroll-menu-arrow--disabled"
hideSingleArrowBooleanhide left/right arrows on first/last pagesfalsefalse
transitionFloat numberHow long animation last, 0 for disablefalse0.4
selectedString or NumberInitial selected itemfalse0
translateNumberInitial offsetfalse0
draggingBooleanAllow drag items by mouse(and touch)falsetrue
clickWhenDragBooleanAfter drag end select item under cursor( if any)falsefalse
menuClassStringClass for componentfalse'horizontal-menu'
arrowClassStringClass for arrowfalse'scroll-menu-arrow'
wrapperClassStringClass for wrapper in componentfalse'menu-wrapper'
innerWrapperStyleObjectStyles inner wrapperfalse{whiteSpace: 'nowrap', textAlign: 'left', userSelect: 'none'}
innerWrapperClassStringClass for inner wrapperfalse'menu-wrapper--inner'
itemStyleObjectStyles for item wrapperfalse{display: 'inline-block'}
itemClassStringClass for item wrapperfalse'menu-item-wrapper'
itemClassActiveStringClass for active item wrapperfalse'active'
menuStyleObjectStyles for root menu componentfalse{display: 'flex', alignItems: 'center', userSelect: 'none'}
wrapperStyleObjectStyle for outer wrapperfalse{overflow: 'hidden', userSelect: 'none'}
onSelectFunctionCallback when item selected, return item keyfalsenull
onUpdateFunctionCallback when menu position changed, return { translate: 0 }falsenull
scrollToSelectedBooleanScroll to selected props passed on mount and when props changedfalsefalse
scrollByNumberHow many menu items to scroll, 0 for all visiblefalse0
inertiaScrollingBooleanUse inertia for scrolling, duration depends on transition and slowdownfalsefalse
inertiaScrollingSlowdownFloat NumberSlow down factor for inertia scrollingfalse0.25
useButtonRoleBooleanAdding role="button" to every itemfalsetrue

Programmaticaly change things

You can scroll left/right via componentRef.handleArrowClick() and componentRef.handleArrowClickRight() functions.

Can get other properties in component state - const { leftArrowVisible, rightArrowVisible, selected, translate } = componentRef.state

Can simulate click with componentRef.onItemClick('item4')

Can select and scroll to item with componentRef.scrollTo('item14')

Gotchas

  • Menu items must have width, if items contains images and images don't loaded yeat it can be problem. Generally component will try to determine width of items, if it can't you can assign ref to component and call $ref.setInitial() manually when items have width for sure.

  • Browser must support requestAnimationFrame or use polyfill.

  • It can doesn't work in IE, and I don't care, I am not a necrophile.(if you need it you can make PR, I will merge)

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

1 Fork the repo:

  • Run npm install in root folder
  • In root folder run npm link
  • Go to example project folder (examples)
  • Run npm install && npm link react-horizontal-scroll-menu
  • Run npm run start in root folder and after that in examples folders

2 Write code! Add some feature or fix bug.

3 Check that all tests passed and add tests for your code.

  • You can use npm run test:watch for run tests in watch mode

4 Update readme and example(if needed)

5 Make commit and Pull Request