Skip to content

Commit

Permalink
Merge pull request #40 from SeinopSys/v7
Browse files Browse the repository at this point in the history
Sorry for the delay. I had been out for a while.

Give me a while to try it out for myself and another time to update the README before publishing
  • Loading branch information
bySabi authored May 21, 2021
2 parents f7b2859 + 54d1c76 commit 80540c7
Show file tree
Hide file tree
Showing 18 changed files with 14,085 additions and 2,339 deletions.
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

0 comments on commit 80540c7

Please sign in to comment.