Giter VIP home page Giter VIP logo

scrollbooster's Introduction

ScrollBooster

Enjoyable drag-to-scroll micro library (~2KB gzipped). Supports smooth content scroll via mouse/touch dragging, trackpad or mouse wheel. Zero dependencies.

Easy to setup yet flexible enough to support any custom scrolling logic.

Installation

You can install it via npm or yarn package manager or via script tag:

npm i scrollbooster
yarn add scrollbooster
<script src="https://unpkg.com/scrollbooster@2/dist/scrollbooster.min.js"></script>

Usage

The most simple setup with default settings:

import ScrollBooster from 'scrollbooster';

new ScrollBooster({
    viewport: document.querySelector('.viewport'),
    scrollMode: 'transform'
});

Please note that in order to support IE11 you should replace arrow functions and string templates from code examples to supported equivalents or just use Babel.

Options

Option Type Default Description
viewport DOM Node null Content viewport element (required)
content DOM Node viewport child element Scrollable content element inside viewport
scrollMode String undefined Scroll technique - via CSS transform or natively. Could be 'transform' or 'native'
direction String 'all' Scroll direction. Could be 'horizontal', 'vertical' or 'all'
bounce Boolean true Enables elastic bounce effect when hitting viewport borders
textSelection Boolean false Enables text selection inside viewport
inputsFocus Boolean true Enables focus for elements: 'input', 'textarea', 'button', 'select' and 'label'
pointerMode String 'all' Specify pointer type. Supported values - 'touch' (scroll only on touch devices), 'mouse' (scroll only on desktop), 'all' (mobile and desktop)
friction Number 0.05 Scroll friction factor - how fast scrolling stops after pointer release
bounceForce Number 0.1 Elastic bounce effect factor
emulateScroll Boolean false Enables mouse wheel/trackpad emulation inside viewport
preventDefaultOnEmulateScroll String false Prevents horizontal or vertical default when emulateScroll is enabled (eg. useful to prevent horizontal trackpad gestures while enabling vertical scrolling). Could be 'horizontal' or 'vertical'.
lockScrollOnDragDirection String false Detect drag direction and either prevent default mousedown/touchstart event or lock content scroll. Could be 'horizontal', 'vertical' or 'all'
dragDirectionTolerance Number 40 Tolerance for horizontal or vertical drag detection
onUpdate Function noop Handler function to perform actual scrolling. Receives scrolling state object with coordinates
onClick Function noop Click handler function. Here you can, for example, prevent default event for click on links. Receives object with scrolling metrics and event object. Calls after each click in scrollable area
onPointerDown Function noop mousedown/touchstart events handler
onPointerUp Function noop mouseup/touchend events handler
onPointerMove Function noop mousemove/touchmove events handler
onWheel Function noop wheel event handler
shouldScroll Function noop Function to permit or disable scrolling. Receives object with scrolling state and event object. Calls on pointerdown (mousedown, touchstart) in scrollable area. You can return true or false to enable or disable scrolling

List of methods

Method Description
setPosition Sets new scroll position in viewport. Receives an object with properties x and y
scrollTo Smooth scroll to position in viewport. Receives an object with properties x and y
updateMetrics Forces to recalculate elements metrics. Useful for cases when content in scrollable area change its size dynamically
updateOptions Sets option value. All properties from Options config object are supported
getState Returns current scroll state in a same format as onUpdate
destroy Removes all instance's event listeners

Full Example

const viewport = document.querySelector('.viewport');
const content = document.querySelector('.scrollable-content');

const sb = new ScrollBooster({
  viewport,
  content,
  bounce: true,
  textSelection: false,
  emulateScroll: true,
  onUpdate: (state) => {
    // state contains useful metrics: position, dragOffset, dragAngle, isDragging, isMoving, borderCollision
    // you can control scroll rendering manually without 'scrollMethod' option:
    content.style.transform = `translate(
      ${-state.position.x}px,
      ${-state.position.y}px
    )`;
  },
  shouldScroll: (state, event) => {
    // disable scroll if clicked on button
    const isButton = event.target.nodeName.toLowerCase() === 'button';
    return !isButton;
  },
  onClick: (state, event, isTouchDevice) => {
    // prevent default link event
    const isLink = event.target.nodeName.toLowerCase() === 'link';
    if (isLink) {
      event.preventDefault();
    }
  }
});

// methods usage examples:
sb.updateMetrics();
sb.scrollTo({ x: 100, y: 100 });
sb.updateOptions({ emulateScroll: false });
sb.destroy();

Browser support

ScrollBooster has been tested in IE 11, Edge and other modern browsers (Chrome, Firefox, Safari).

Special thanks

David DeSandro for his talk "Practical UI Physics".

License

MIT License (c) Ilya Shubin

scrollbooster's People

Contributors

alexwidua avatar alirezamirian avatar bragovo avatar bramdoppen avatar dependabot[bot] avatar homerjam avatar ilyashubin avatar joshdavenport avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scrollbooster's Issues

Possible to let scrollTo use translate3d in stead of translate

I have a question > is it possible to let scrollTo use translate3d in stead of translate. We are using this function the whole time. And when we add hover effects (transform) on elements that are in the content area, animations start to lag a bit.

Thanks for this great piece of code by the way πŸ‘

updateMetrics works incorrectly

When scroll position not in (0, 0) and we update the size of the scroll area, updateMetrics function works incorrectly, In the result, we get bigger scrollable area than it actually is

touch tap doesn't work

I have tab elements, and I made them scrollable. I can't change tabs because you made return in toucstart event.

If the scroll target contains textbox or selectbox, you can not focus on those input elements.

I am Japanese. I am sorry if my English is strange.
You can use the focus function in the onClick function to focus on the textbox but can not display the selectbox drop-down list.
Is there a solution?

<script type="text/javascript">
    $(function() {
        $(document).ready(function() {
            let viewport = document.querySelector(".viewport");
            let content = viewport.querySelector(".viewport-content");
            let sb = new ScrollBooster({
                "viewport": viewport,
                "content": content,
                "textSelection": false,
                "friction": 0.5,
                "mode": 'x',
                "onUpdate": (data)=> {
                    viewport.scrollLeft = data.position.x
                },
                "onClick": (data, event) => {
                    // Focus on input element
                    event.target.focus();
                }
            })
        });
    });
</script>


<div class="table-responsive viewport">
    <table class="table table-bordered table-sm text-nowrap viewport-content">
        <thead>
            <tr>
                <th>AAAAAAAAAA</th>
                <th>BBBBBBBBBB</th>
                <th>CCCCCCCCCC</th>
                <th>DDDDDDDDDD</th>
                <th>EEEEEEEEEE</th>
                <th>FFFFFFFFFF</th>
                <th>GGGGGGGGGG</th>
                <th>HHHHHHHHHH</th>
                <th>IIIIIIIIII</th>
                <th>JJJJJJJJJJ</th>
                <th>KKKKKKKKKK</th>
                <th>LLLLLLLLLL</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td><input type="checkbox" class="w-100"></td>
                <td><input type="text" class="w-100"/></td>
                <td><input type="text" class="w-100"/></td>
                <td><input type="text" class="w-100"/></td>
                <td><input type="text" class="w-100"/></td>
                <td><input type="text" class="w-100" readonly="readonly"/></td>
                <td><input type="text" class="w-100" readonly="readonly"/></td>
                <td><input type="text" class="w-100"/></td>
                <td>
                    <select class="w-100">
                        <option value="0">000</option>
                        <option value="1">111</option>
                        <option value="2">222</option>
                        <option value="3">333</option>
                        <option value="4">444</option>
                    </select>
                </td>
                <td>
                    <select class="w-100">
                        <option value="10">10</option>
                        <option value="20">20</option>
                    </select>
                </td>
                <td><input type="text" class="w-100"/></td>
                <td><input type="checkbox"class="w-100"/></td>
            </tr>
        </tbody>
    </table>
</div>

'isDragging' is incorrectly read as true when querying via 'getState()'

Hi, first of all thanks for the great library.

I'm currently having an issue where isDragging state is set to true but shouldn't be. This is reproducible when completing a mouse drag in the scrollable area then querying the state without clicking in the scrollable area again.

It seems to be to do with how we determine isDragging state in getState().

isDragging: !!(this.dragOffset.x || this.dragOffset.y),

Instead of using this.isDragging which is set to false on mouseup it relys on dragOffset which doesn't seem to be reset until another pointer event occurs.

Couldn't find any other issues relating to this so I am wondering if I am missing something?

Thanks in advance :)

Detecting when the scrollable element is at the start or end of the scrollable viewport

Hey!

We want to add navigation arrows on each side of the scrollable viewport that can also trigger scroll (by a predefined amount of pixels). When we reach the end or the start of the scrollable viewport, we would like to hide the corresponding arrow.

Taking a quick look at the code base, it seems like you are already calculating those metrics at applyBoundForce(). Do you think you can add those metrics to the getState method, thus making them available in the onUpdate() callback?

Thanks!

Vertical scroll on mobile

Using the following options:

new ScrollBooster({
    viewport: scrollCanvas,
    scrollMode: 'transform',
    direction: "horizontal'
});

Scrolling the page on the Y axis with drag doesn't work, because the viewport catches the events. The users cannot scroll the page on the Y axis, if the canvas occupies the whole screen on mobile.

I can provide an example of a page where the correct behaviour can be observed (our services section): https://www.instrument.com/what-we-do/

The possible fix is to check the first pointer drag event. If it's not in the same direction as the configured direction, then do nothing. Perhaps a more robust solution is to calculate the angle of the two lines and apply a threshold.

Add Changelog

Hi,

Could you add the changelog for V2 release ? Current I use v1 so just wonder is it ok to upgrade to v2 and what new in v2 ?

Thanks!

Doesn't work horizontal scrolling on mousewheel

It doesn't work

new ScrollBooster({
    viewport,
    content,
    direction: 'horizontal',
    emulateScroll: true,
    onUpdate: (state) => {
        content.style.transform = `translateX(${-state.position.x}px)`
    }
})

If you use native scrolling, scrolling is handled by browser itself:

new ScrollBooster({
  viewport,
  content,
  direction: 'horizontal',
  onUpdate: (state) => {
    viewport.scrollLeft = state.position.x;
  }
})

Originally posted by @ilyashubin in #19 (comment)

JsFiddle: https://jsfiddle.net/eq3cntow/93/

event.touches is undefined

Trying in mobile screen in Firefox, i receive error when trying to scroll.

Version: 3.0.2

  417 | }
  418 | 
> 419 | const eventData = isTouch ? event.touches[0] : event;
      | ^  420 | const { pageX, pageY, clientX, clientY } = eventData;
  421 | 
  422 | this.dragOffset.x = pageX - dragOrigin.x;```

setPosition doesn’t smoothly scroll

Is there a way to make setPosition smoothly scroll?

scroll() {
	this.scrollBooster.setPosition({
		x: this.scrollBooster.getUpdate().position.x += 200
	});
}

This is attached to a button that will scroll the content. I tried to maually set the translate:

scroll() {
	contentElement.style.transform = `translateX(${-data.position.x}px)`
}

But this gets overidden instantly and set back to the current position stored with ScollBooster.

'Type not assignable...' when not supplying every option parameter to constructor when using TypeScript JS file checking

We're using TypeScript with JS file checking enabled in our project. What that means is that TypeScript will check JS files for JSDoc definitions and interpret them as types.
scrollbooster's index file contains JSDocs definitions:

image

When I try to create a new ScrollBooster instance with the same options as suggested in the README.md like this:

new ScrollBooster({
    viewport: document.querySelector('.viewport'),
    scrollMode: 'transform'
});

... TypeScript complains about missing parameters:

TS2345: Argument of type '{ viewport: HTMLElement; scrollMode: string; }' is not assignable to parameter of type '{ viewport: Element; content: Element; direction: string; pointerMode: string; scrollMode: string; bounce: boolean; bounceForce: number; friction: number; textSelection: boolean; ... 5 more ...; shouldScroll: Function; }'.
  Type '{ viewport: HTMLElement; scrollMode: string; }' is missing the following properties from type '{ viewport: Element; content: Element; direction: string; pointerMode: string; scrollMode: string; bounce: boolean; bounceForce: number; friction: number; textSelection: boolean; ... 5 more ...; shouldScroll: Function; }': content, direction, pointerMode, bounce, and 9 more.

That's because in the JSDocs comments of ScrollBooster's index file, non-essential parameters are not marked as optional. In JSDocs, you can mark parameters as optional by wrapping the parameter name in brackets ( [] ). When I do that for all the non-essential parameters, TypeScript stops complaining and my example works πŸŽ‰ .

@ilyashubin I wanted to open a PR, but I can't seem to create a branch for this repo.

Implement horizontal scrolling using mouse wheel + smooth scrolling doesn't work using mouse wheel

Hello,

This library is capable of implementing horizontal scrolling using mouse wheel, but there is currently no way to do this.

I managed to get it to work simply by changing deltaX to deltaY in here:

this.scrollOffset.x = -event.deltaX;

However, when I did this, I noticed that the horizontal scrolling via mousewheel does indeed work, but it does not smoothly scroll and instead just snaps in place.

This will be one hell of a powerful library if it can be used for many uses cases like this.

Quick webm showing behaviour: http://i.venner.io/2020-03-12_20-03-12.webm

destroy() is incomplete.

Thanks for this great plugin. First of all, thank you.

I found an event that I couldn't delete with destroy().
The following events cannot be deleted because there was a problem while attaching and removing the scroollBooster.

this.props.content.addEventListener("load",this.events.contentLoad,!0)
this.props.content.removeEventListener("load",this.events.contentLoad)

The cause is that the arguments don't match.

this.props.content.removeEventListener("load",this.events.contentLoad,!0)

Translated with www.DeepL.com/Translator (free version)

onPointerDown/onPointerUp options not working

It doesn't seem that it's posting a mouseup or mousedown listener. Example:

const wrapper = document.querySelector('.wrapper');
const content = wrapper.querySelector('.content');

new ScrollBooster({
    viewport: wrapper,
    content: content,
    scrollMode: 'transform',
    onPointerDown() {
      wrapper.style.backgroundColor = '#6fd0c7';
    },
    onPointerUp() {
      wrapper.style.backgroundColor = '#6f9ed0';
    },
    onPointerMove() {
      wrapper.style.backgroundColor = 'yellow';
    }
});

Working pen: https://codepen.io/kpagcha/pen/jOmWjJa

Cannot drag elements

Hi guys,

Same with the title, having issues with dragging if I added the option of bounce set to false:

`js
import React from "react";
import ScrollBooster from "scrollbooster";

import styles from "../styles/Home.module.css";

export default function HomePage() {
const viewportRef = React.useRef();
const contentRef = React.useRef();
let posX = 1;
let posY = 1;
let move = false;

React.useEffect(() => {
    // const [viewport, scrollbooster] = useScrollBoost({
    //     direction: "all",
    //     scrollMode: "transform",
    // });

    const SB = new ScrollBooster({
        viewport: viewportRef.current,
        content: contentRef.current,
        emulateScroll: false,
        bounce: true,
        onUpdate: (data) => {
            posX = Math.ceil(data.position.x);
            posY = Math.ceil(data.position.y);
            contentRef.current.style.transform =
                "translate(" +
                -data.position.x +
                "px, " +
                -data.position.y +
                "px)";
        },
        onClick: (state, event, isTouchDevice) => {
            // prevent default link event
            console.log({ state, event, isTouchDevice });
        },
    });
}, []);

return (
    <div className={styles.container} ref={viewportRef}>
        <div className={styles.content} ref={contentRef}>
            <h2 className={styles.heading}>Drag to scroll</h1>
            <h3>Some Content</h2>
            <h3>Some Content</h2>
            <h3>Some Content</h2>
            <h3>Some Content</h2>
            <h3>Some Content</h2>
            <h3>Some Content</h2>
            <h3>Some Content</h3>
        </div>
    </div>
);

}
`

`css
.container {
min-height: 100vh;
overflow: hidden;
position: relative;
}

.content {
background: #b2e1f8;
color: rgb(27, 82, 202);
width: 100vw;
height: 100vh;
}

.heading {
margin: 0;
}

`

Mac safari 10/11 version not working

Hi Ilyashubin,

It's working well in Chrome, Firefox and safari 12+ but not in mac safari 10/11, facing issues with the package and my application is stable before adding this package.

Even your reference website (https://ilyashubin.github.io/scrollbooster/) also not working in mac safari 10/11 -
Unexpected token '...'. Expected a property name.

Please resolve the issue.

scrollTo blocks dragging until animation is finished

I'm working on a project that depends on scrollTo for navigating between specific coordinates on the page. it works smoothly, but I also want the user to be able to stop the animation (triggered by scrollTo) if the user starts to drag and give the control back to the user.

Jumpy behavior when dragging with mouse after scrolling with touchpad

I've a horizontal scroll view that can be scrolled my touch, touchpad or by dragging with scrollbooster.
When the scroll view is scrolled using the touchpad and afterwards dragged by scrollbooster, I get jumpy behavior :/

Currently I've worked around it by updating the scrollbooster offset in the shouldScroll method:

//Jumpy behavior workaround
shouldScroll: () => {
        sb.setPosition({x: scrollView.scrollLeft});
        return true
}

Missing option to choose between mouse and touch

I'm missing a way to only enable scrollbooster for mouse or touch, currently I use the shouldScroll callback to only make it work with mouse events:

//Only use scrollbooster for mouse interaction
shouldScroll: (data, event) => {
        const isTouch = !!(event.touches && event.touches[0]);
        return !isTouch;
}

How to get scroll position to use in slider navigation

This is a brilliant plugin, just what I need. I'm using it as a horizontal slider on desktop, but want to show a navigation element below it which goes from 0% to 100% depending on the position of the scroller content.

Anybody know how to return a value from 0% to 100% on scroll?

I've checked out the onUpdate event, and can see the position.x shows 0 at the start, but can't figure out how to get 100%

Method scrollPosition

Hi, first of all, great work!!
I was working with Scrollbooster and I just noticed that there could be a great addition
scrollPosition
where we could pass a coordinate and the container moves to it in a smooth manner
Similar to - window.scrollBy(x-coord, y-coord);
We are working on it, don't know if with the best perspective, but hopefully, we can show you guys something

scrollTo issues

Is it possible to control scrollTo animation scroll duration?

Also, how would one go about controlling max X in scrollTo? It seems like onUpdate is not triggered from within setPosition and my checks there are completely ignored (if(state.position.x < 0) tabsSb.scrollTo({x: 0});). I want to set absolute min / max values that includes scrollTo as well, not just manual scroll.

Thanks!

click event

it would be great to have some option to avoid clicks when scrolling.

It can be done manually, comparing coordinates in mousedown with coordinates in click, but I think it is a common use case, so I think an option would be better.

Drag to scrool whole website

I try like

new ScrollBooster({
    viewport: $('body')[0],
    scrollMode: 'native',
    textSelection: true,
});

But not work, is possible in this lib ?

right click

hello.
thank you for your great project!

I have a suggestion.
How about ignoring right-clicks?(contextmenu event)

If you right-click on the content, the content will always be dragged, even if you release the button.

I don't think there is any disadvantage to ignoring the contextmenu event.

I would be happy if you could consider it.

bumbing when content not fully loaded

I am using Scroll Booster for an image slideshow. I noticed that Scroll Booster bumps, if the images were not fully loaded at the time I start scrolling.

So basically, I load the website only shortly, start scrolling > bug
If I load the website and wait a while before I start scrolling > I can scroll till the end.

<script type="text/javascript">
			jQuery(document).ready(function( $ ){
				let viewport = document.querySelector('#photo_slider')
				let content = viewport.querySelector('.photos')

				let sb = new ScrollBooster({
				  viewport,
				  content,
				  mode: 'x',
				  onUpdate: (data)=> {
					viewport.scrollLeft = data.position.x
				  }
				})
			});
</script>

Please find here the example I am working on. It would be great to get some support on this:
http://boenemann.com/photo/ukraine/

Editable field

Hi i have conet editable div is not activated when use scrollbooster, any idea to fix ?

link drag issue

Hi, Ilya!

If there are links in draggable container, they will be fire click event while dragging.

Position problem.

Hello! I work with your library and find some problems. When i use touch devices like a (iphone, ipad etc) scroll position not updated. All time back to start. How i should solved this problem. On your site demo all works perfect

Internet Explorer 11 - Not working

Hello, thanks for this wonderful plugin. It saved me tons of time.

The last example on demo page is not working on IE11 but its not showing any error in console.

My example doesn't work on Internet explorer 11 and it also throws syntax error in console. I copied the code from your examples.

if ( $('.drag-viewport').length ) {

  let viewport = document.querySelector('.drag-viewport');
  let content = viewport.querySelector('.drag-viewport-content');
  let img = content.querySelector('.cards-grid');

  let sb = new ScrollBooster({
    viewport: viewport,
    content: content,
    emulateScroll: true,
    onUpdate: (data)=> { // syntax error
      content.style.transform = `translate(
        ${-data.position.x}px,
        ${-data.position.y}px
      )`
    },
    // prevent click on drag
    onClick: (data, event) => {
      if (Math.abs(data.dragOffsetPosition.x) > 5) {
        event.stopPropagation();
      }
    },
  })

  // set viewport position to the center of an image
  let offsetX = img.scrollWidth - viewport.offsetWidth
  let offsetY = img.scrollHeight - viewport.offsetHeight
  sb.setPosition({
    x: offsetX / 2,
    y: offsetY / 2
  })

}

Unable to test component using Scrollbooster

Hi!

I have a component which relies on refs and Scrollbooster (see below). When trying to mount the component with Enzyme I get an error saying:

at processImmediate (timers.js:658:5) ReferenceError: Element is not defined
at new t (/home/vikenfalk/third-party-client/tp-client/node_modules/scrollbooster/dist/webpack:/ScrollBooster/src/index.js:76:70)

If I log the reference that I'm passing to the Scrollbooster it looks fine and identical to what I can see when I run the actual application. The error seems to be related to JSDOM, but I'm wondering if anybody knows a way around this issue so that I can mount the component and test the calculations within the UseEffect function?

const ProgressBarScroller = (props) => {
    const [progressbarWrapperRef, progressBarTaskRef, progressBarRef] = [
        useRef(null),
        useRef(null),
        useRef(null)
    ];
    const getElementWidth = (refName) => refName.current.getBoundingClientRect().width;

    useEffect(() => {
        if (!progressBarTaskRef.current || !progressBarRef.current || !progressbarWrapperRef.current) return;

        const taskWidth = getElementWidth(progressBarTaskRef);
        const progressBarWidth = getElementWidth(progressBarRef);
        const progressbarWrapperWidth = getElementWidth(progressbarWrapperRef);

        const middleOfActiveTask =
            (props.currentTaskIndex + 1) * taskWidth - taskWidth / 2;
        const requestedX = middleOfActiveTask - progressbarWrapperWidth / 2;
        const maxPossibleX = progressBarWidth - progressbarWrapperWidth;


        const scroller = new scrollBooster({
            viewport: progressbarWrapperRef.current,
            direction: 'horizontal',
            scrollMode: 'transform',
            friction: 0.2
        });

        /**
         * returns 0 if requested X position is lower than minimum.
         * returns the highest possible X position if requested X is higher than maximum.
         * Otherwise returns requested X position.
         * @returns {number}
         */
        const getValidXPosition = () => {
            return requestedX <= 0 ? 0
                : requestedX >= maxPossibleX ? maxPossibleX
                    : requestedX;
        };

        (function moveToDefaultPosition() {
            scroller.setPosition({
                x: getValidXPosition(),
                y: 0
            });
        })();

        //Cleans up ScrollBooster on unmount
        return () => {
            scroller.destroy();
        };
    }, []);

    return (
        <div className={'cs-progressbar'} ref={progressbarWrapperRef}>
            <ul className={`cs-progressbar__list`} ref={progressBarRef}>
                {props.tasks.map((task, index) => {
                    return (
                        <ProgressBarTask
                            {...task}
                            key={task.id}
                            innerRef={
                                props.currentTaskIndex === index
                                    ? progressBarTaskRef
                                    : null
                            }
                        />
                    );
                })}
            </ul>
        </div>
    );
};
library version
enzyme 3.11.0
react 16.13.1
react-dom 16.13.1
react-test-renderer 17.0.1
scrollbooster 2.3.0

Bounce drag amount/offset

There is option to set bounceForce, but how to control bounce offset on drag? Currently you can drag content out of viewport and on release it bounces back to start.
Can you add option to control that offset?

Allow inputFocus on [contenteditable]

Currently any elements that should be able to receive input because of the contentEditable property are not focusable. Can we get support for those elements as well?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.