Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .babelrc

This file was deleted.

10 changes: 10 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 120
trim_trailing_whitespace = true
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
src/scrollchor-old.jsx
lib/
rollup.config.js
77 changes: 77 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"env": {
"browser": true,
"es6": true
},
"extends": [
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"airbnb",
"plugin:import/typescript",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2018,
"sourceType": "module",
"project": "./tsconfig*.json"
},
"plugins": [
"react",
"@typescript-eslint",
"import-newlines"
],
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error",
"react/prop-types": "off",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": "error",
"import/extensions": [
"error",
"never"
],
"react/jsx-filename-extension": [
"error",
{
"extensions": [
".tsx"
]
}
],
"no-void": "off",
"react/jsx-props-no-spreading": "off",
"object-curly-newline": [
"error",
{
"multiline": true,
"minProperties": 5
}
],
"import-newlines/enforce": [
"error",
4,
100
],
"import/prefer-default-export": "off"
},
"settings": {
"import/parsers": {
"@typescript-eslint/parser": [
".ts",
".tsx"
]
},
"import/resolver": {
"typescript": {}
},
"react": {
"version": "detect"
}
}
}
6 changes: 6 additions & 0 deletions .huskyrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"hooks": {
"pre-commit": "lint-staged",
"pre-push": "npm run build"
}
}
4 changes: 4 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ CHANGELOG.md
CONTRIBUTING.md
src
package-lock.json*
.eslintrc
.eslintignore
tsconfig.json
rollup.config.js
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
## master (unreleased)

## 7.0.0

This new major version contains breaking changes.

- Everything has been rewritten in TypeScript, which brings with it published type definitions
- The default export has been removed in favor of a named export; `import Scrollchor` must be replaced with `import { Scrollchor }`
- The `simulateClick()` API has been removed entirely
- Scrollchor is now a function component and makes use of hooks introduced in React v16.8, which necessitated a minimum version bump for this `peerDependency`
- `animation.easing` configuration is now documented and compatible with all the easing functions provided by [jquery-easing](https://github.com/danro/jquery-easing/blob/master/jquery.easing.js)
- Added two additional built-in easing types for _ease_ of use, borrowed from jQuery (`linear`, `swing`)

## 6.0.0

`Scrollchor` React component now belong to `Some React Component` Organization Team. This move will ensure its future development and manteniance.
Expand Down
182 changes: 77 additions & 105 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@
[![npm downloads](https://img.shields.io/npm/dm/react-scrollchor.svg?style=flat-square)](https://www.npmjs.com/package/react-scrollchor)
[![Donate](https://img.shields.io/badge/$-support-green.svg?style=flat-square)](https://paypal.me/bySabi/10)

> A React component for scroll to `#hash` links with smooth animations.
> A React component for scrolling to `#hash` links with smooth animations.
> Scrollchor is a mix of `Scroll` and `Anchor`, a joke name for a useful component.

See it in action:
* demo [video](https://github.com/some-react-components/react-scrollchor/blob/example/demo/scrollchor.webm?raw=true)
* example [page](https://some-react-components.github.io/react-scrollchor/) and [source code](https://github.com/some-react-components/react-scrollchor/tree/example)


`hash` is the `id` of a HTML tag on current page.

`hash` is the `id` attribute of an HTML tag on the current page.

## Installation

Expand All @@ -23,17 +20,24 @@ See it in action:
npm install react-scrollchor --save
```

### yarn

```bash
yarn add react-scrollchor
```

### Dependencies
* User should provide their own `React` package

You must have React (≥16.8.0) installed in your project before trying to use this component. This minimum version constraint represents the React version which [introduced hooks](https://reactjs.org/docs/hooks-intro.html).


## Usage

```js
import Scrollchor from 'react-scrollchor';
```
```js
export default (props) => (
import { Scrollchor } from 'react-scrollchor';
import { Navbar, NavItem, Page, Section } from './components';

const LandingPage = (props) => (
<Page>

<Navbar brand={brand} className="navbar-fixed-top">
Expand All @@ -44,128 +48,95 @@ export default (props) => (
</Navbar>


<Section id="sample-code">
<Section id="sample-code">
<div style={{ height: '100vh' }} />
</Section>

</Section>
<div id="features">
<div style={{ height: '100vh' }} />
</div>

<div id="features">
<footer id="footer">
<div style={{ height: '100vh' }} />
</footer>

</div>
</Page>
);

<footer id="footer">
export default LandingPage;
```

</footer>
## Props

</Page>
```
The package ships with TypeScript type definitions to help with IDE autocompletion, but the sections below should give you a quick rundown of each prop if you prefer this format. Any props not listed below are passed directly on to the underlying `<a>` tag, except for `href` and `onClick`.

## Prop types
```js
propTypes: {

/**
* id attribute of the target DOM node
* - `#` can be omitted
* - let it blank, `to = ''`, for scroll to page top
* - this prop is required
*/
to: PropTypes.string.isRequired,

/**
* id attribute of the scrollable DOM node
* - `#` can be omitted
* - uses the root element of the document if omitted
*/
target: PropTypes.string,

/**
* scroll smooth animation can be customized
* Accepted options, Ex: (default)
* { offset: 0, duration: 400, easing: easeOutQuad }
*/
animate: PropTypes.object,

/**
* callback function triggered before scroll to #hash
* @param1 Received click event
*/
beforeAnimate: PropTypes.func,

/**
* callback function triggered after scroll to #hash
* @param1 Received click event
*/
afterAnimate: PropTypes.func

/**
* enable/disable update browser history with scroll behaviours
* Default to `false`
*/
disableHistory: PropTypes.bool
}
```
### Reactive `props`
Update `props` will re-render `Scrollchor` element
The `to` prop controls the final `href` prop, and `onClick` is used internally to perform the scrolling. If you need to run some code when the link is clicked use the `beforeAnimate` prop instead.

Example: [updating "to" prop](https://github.com/some-react-components/react-scrollchor/blob/example/src/App.js#L28)
### `to: string`

## Custom animations
The anchor (id) to which this link should scroll to. Any leading `#` will be stripped from this value.

Animation behavior can be customized:
### `target?: string`

```js
<Scrollchor to="#aboutus" animate={{offset: 20, duration: 600}} className="nav-link">Home</Scrollchor>
```
The element scrolling will be performed on when clicked. Leading `#` will be stripped here as well.

### default animation settings
```js
{ offset: 0, duration: 400, easing: easeOutQuad }
```
This setting is equivalent to default jQuery.animate `easing: swing`
Scrollchor works within any scrollable parent container. If no target is provided (or the target element is not found on the page), the default is scrolling both the `<html>` and `<body>` elements simultaneously.

### more `Easing` functions
### `animate?: Partial<AnimateConfig>`

* [jQuery easings](http://api.jqueryui.com/easings/)
* [Robert Penner's Easing Functions](http://robertpenner.com/easing/)
* [Javascript source code](https://github.com/danro/jquery-easing/blob/master/jquery.easing.js)
The smooth scrolling animation can be customized using this prop. Three pre-defined easing functions are exported by the package: `easeOutQuad`, `swing`, `linear`. When not provided, the default looks like this:

```ts
import { AnimateConfig, easeOutQuad } from 'react-scrollchor';

## `before` and `after` Animate callbacks
Use these callbacks to trigger behaviors like: update state, load async stuff, etc.
```js
<Scrollchor to="#aboutus" afterAnimate={() => updateState(this)}>Home</Scrollchor>
const defaultAnimate: AnimateConfig = {
offset: 0,
duration: 400,
easing: easeOutQuad,
};
```

## Simulate click API
Scrollchor includes a dedicate API to do animate scroll programmatically that works like normal click events using `simulateClick()`.
* `offset?: number` &mdash; Additional pixels to scroll relative to the target element (supports negative values, e.g. for fixed position headers)
* `duration?: number` &mdash; Length of the animation in milliseconds
* `easing?: ScrollchorEasingFunction` &mdash; Easing function to calculate the animation steps. Pass a function that matches the exported interface for a custom easing.

Example: [using simulateClick](https://github.com/some-react-components/react-scrollchor/blob/example/src/App.js#L16)
| # | Parameter | Meaning |
|---|-----------|---------|
|0|percent|Percent completed of the animation (decimal, `0.0` to `1.0`)|
|1|elapsedTime|Time elapsed since the animation began, in ms|
|2|startValue|Static value set to `0`|
|3|valueChange|Static value set to `1`|
|4|duration|Duration of the animation, in ms|

When used programmatically, some use-cases don't need `anchor tags`. On these cases use childless `Scrollchor`.
Returns a decimal indicating how close the animation is to the end value (`0` = start, `1` = finished, `1.2` = 20% over the end value, think "bounce" effects)

### Childless `Scrollchor`
This component will render `null` and the user is reponsible for storing the component [reference](https://facebook.github.io/react/docs/refs-and-the-dom.html), Ex: [childless](https://github.com/some-react-components/react-scrollchor/blob/example/src/App.js#L23)
```js
<Scrollchor ref={ref => (this._back = ref)} to="_back" />
```
Example: [calling `simulateClick()` on childless `ref`](https://github.com/some-react-components/react-scrollchor/blob/example/src/App.js#L16)
```js
_afterAnimate = () => {
this.setState({ to: this._iterator.next().value });
setTimeout(() => this._back.simulateClick(), 1000);
};
The default values can be customized all at once or individually by providing only the properties you want to override. For example:

```jsx
import { Scrollchor, linear } from 'react-scrollchor';

const HomeLink = () => (
<Scrollchor to="home" animate={{ duration: 1000, easing: linear }}>
Home
</Scrollchor>
);
```

## Scrollable ancestor container
Scrollchor works within any scrollable parent container. The root element of the `document` will be choose if none is specified.
You can find additional easing functions at these links:

* [Robert Penner's Easing Functions](http://robertpenner.com/easing/)
* [Javascript source code](https://github.com/danro/jquery-easing/blob/master/jquery.easing.js)


Hosted example show how to use a different container using prop `target`.
* Click `Within scrollable container` checkbox: [hosted example](https://some-react-components.github.io/react-scrollchor/)(full example below)
### `beforeAnimate: MouseEventHandler` / `afterAnimate: MouseEventHandler`

You can use these callbacks to trigger behaviors like: update state, load async stuff, etc. when either stage happens. The functions receive the originating `MouseEvent` as their only argument, the return value is not used.

## Full Example
`beforeAnimate` is triggered before the animation starts, i.e. immediately when the link is clicked, while `afterAnimate` is called once the animation has finished.

[react-scrollchor--example](https://github.com/some-react-components/react-scrollchor/tree/example)
```js
<Scrollchor to="#aboutus" afterAnimate={() => setActive('home')}>Home</Scrollchor>
```

## Credits

Expand All @@ -174,6 +145,7 @@ Hosted example show how to use a different container using prop `target`.

### maintainers
* xehpuk <> [@xehpuk](https://github.com/xehpuk)
* SeinopSys <> [@SeinopSys](https://github.com/SeinopSys)

### contributors
* Jean Chung <> [@jeanchung](https://github.com/jeanchung)
Expand Down
Loading