Skip to content

Commit f48a0f6

Browse files
committed
intial import
1 parent 5dd5aad commit f48a0f6

File tree

9 files changed

+6213
-0
lines changed

9 files changed

+6213
-0
lines changed

.babelrc.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const BABEL_ENV = process.env.BABEL_ENV
2+
const building = BABEL_ENV != undefined && BABEL_ENV !== 'cjs'
3+
4+
const plugins = []
5+
6+
if (process.env.NODE_ENV === 'production') {
7+
plugins.push('dev-expression')
8+
}
9+
10+
if (BABEL_ENV === 'cjs') {
11+
plugins.push('babel-plugin-add-module-exports')
12+
}
13+
14+
module.exports = {
15+
presets: [
16+
'@babel/preset-typescript',
17+
[
18+
'@babel/preset-env',
19+
{
20+
loose: true,
21+
modules: building ? false : 'commonjs',
22+
},
23+
],
24+
],
25+
plugins: plugins,
26+
}

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,10 @@ typings/
5757
# dotenv environment variables file
5858
.env
5959

60+
dist
61+
es
62+
typings
63+
umd
64+
/*.js
65+
!.babelrc.js
66+
!rollup.config.js

README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
[![CircleCI Status](https://img.shields.io/circleci/project/github/stipsan/smooth-scroll-into-view-if-needed.svg?style=flat-square)](https://circleci.com/gh/stipsan/smooth-scroll-into-view-if-needed)
2+
[![npm stat](https://img.shields.io/npm/dm/smooth-scroll-into-view-if-needed.svg?style=flat-square)](https://npm-stat.com/charts.html?package=smooth-scroll-into-view-if-needed)
3+
[![npm version](https://img.shields.io/npm/v/smooth-scroll-into-view-if-needed.svg?style=flat-square)](https://www.npmjs.com/package/smooth-scroll-into-view-if-needed)
4+
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release)
5+
![smooth-scroll-into-view-if-needed](https://user-images.githubusercontent.com/81981/39338604-0bff23f2-49c4-11e8-9929-2f2b74a67b3c.png)
6+
7+
This is a [ponyfill](https://ponyfill.com) for smooth scrolling
8+
`scroll-into-view-if-needed`.
9+
10+
## [Demo](https://scroll-into-view-if-needed.netlify.com/)
11+
12+
## Install
13+
14+
```bash
15+
yarn add smooth-scroll-into-view-if-needed
16+
```
17+
18+
## Usage
19+
20+
```js
21+
import scrollIntoView from 'smooth-scroll-into-view-if-needed'
22+
const node = document.getElementById('hero')
23+
24+
// If all you want is for all your users to have stuff smooth scroll into view
25+
scrollIntoView(node, { behavior: 'smooth' })
26+
27+
// combine it with any of the other options
28+
scrollIntoView(node, {
29+
behavior: 'smooth',
30+
scrollMode: 'if-needed',
31+
block: 'nearest',
32+
inline: 'nearest',
33+
})
34+
35+
// It returns a promise that is resolved when the animation is finished
36+
const sequence = async () => {
37+
const slide = document.getElementById('slide-3')
38+
// First smooth scroll to hero
39+
await scrollIntoView(node, { behavior: 'smooth' })
40+
// Then we scroll to a slide in a slideshow
41+
return scrollIntoView(slide, { behavior: 'smooth' })
42+
}
43+
```
44+
45+
### Custom scrolling transition
46+
47+
If the default smooth scrolling ponyfill isn't the duration or easing you want,
48+
you can provide your own scrolling logic by giving `behavior` a callback.
49+
50+
```js
51+
import scrollIntoView from 'smooth-scroll-into-view-if-needed'
52+
const node = document.getElementById('hero')
53+
54+
scrollIntoView(node, {
55+
// Your scroll actions will always be an array, even if there is nothing to scroll
56+
behavior: scrollActions =>
57+
// list is sorted from innermost (closest parent to your target) to outermost (often the document.body or viewport)
58+
scrollActions.forEach(([el, scrollTop, scrollLeft]) => {
59+
// implement the scroll anyway you want
60+
el.scrollTop = scrollTop
61+
el.scrollLeft = scrollLeft
62+
63+
// If you need the relative scroll coordinates, for things like window.scrollBy style logic, just do the math
64+
const offsetTop = el.scrollTop - scrollTop
65+
const offsetLeft = el.scrollLeft - scrollLeft
66+
}),
67+
// all the other options (scrollMode, block, inline) still work, so you don't need to reimplement them (unless you really really want to)
68+
})
69+
```
70+
71+
## More documentation will be added (hang in there)

package.json

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
{
2+
"name": "smooth-scroll-into-view-if-needed",
3+
"description":
4+
"Ponyfill for smooth scrolling elements into view (if needed!)",
5+
"license": "MIT",
6+
"author": "Stian Didriksen",
7+
"homepage": "https://scroll-into-view-if-needed.netlify.com/",
8+
"repository": {
9+
"type": "git",
10+
"url":
11+
"git+https://github.com/stipsan/smooth-scroll-into-view-if-needed.git"
12+
},
13+
"version": "1.0.0",
14+
"main": "index.js",
15+
"files": ["es", "umd"],
16+
"scripts": {
17+
"prebuild": "yarn clean",
18+
"build":
19+
"yarn build:d.ts && yarn build:cjs && yarn build:es && yarn build:umd && yarn build:umd.min",
20+
"build:cjs": "BABEL_ENV=cjs babel src -d . --extensions '.ts'",
21+
"build:d.ts": "tsc --emitDeclarationOnly",
22+
"build:es": "BABEL_ENV=es babel src -d es --extensions '.ts'",
23+
"build:umd":
24+
"BABEL_ENV=umd NODE_ENV=development rollup -c -f umd -o umd/smooth-scroll-into-view-if-needed.js",
25+
"build:umd.min":
26+
"BABEL_ENV=umd NODE_ENV=production rollup -c -f umd -o umd/smooth-scroll-into-view-if-needed.min.js",
27+
"clean": "rimraf 'umd' 'es' 'typings'",
28+
"precommit": "lint-staged",
29+
"dev": "concurrently 'tsc --watch' 'yarn build:cjs --watch'",
30+
"prepublishOnly": "unset npm_config_cafile && yarn build",
31+
"typecheck": "tsc --noEmit"
32+
},
33+
"dependencies": {
34+
"scroll-into-view-if-needed": "^2.0.1-alpha.0"
35+
},
36+
"devDependencies": {
37+
"@babel/cli": "7.0.0-beta.46",
38+
"@babel/core": "7.0.0-beta.46",
39+
"@babel/plugin-external-helpers": "7.0.0-beta.46",
40+
"@babel/preset-env": "7.0.0-beta.46",
41+
"@babel/preset-typescript": "7.0.0-beta.46",
42+
"babel-eslint": "8.2.3",
43+
"babel-plugin-add-module-exports": "0.2.1",
44+
"babel-plugin-dev-expression": "0.2.1",
45+
"babel-plugin-styled-components": "1.5.1",
46+
"concurrently": "3.5.1",
47+
"eslint": "4.19.1",
48+
"eslint-config-prettier": "2.9.0",
49+
"eslint-plugin-import": "2.11.0",
50+
"eslint-plugin-react": "7.7.0",
51+
"husky": "0.14.3",
52+
"lerna": "2.11.0",
53+
"lint-staged": "7.0.5",
54+
"prettier": "1.12.1",
55+
"prettier-package-json": "1.5.1",
56+
"rimraf": "2.6.2",
57+
"rollup": "0.58.2",
58+
"rollup-plugin-babel": "4.0.0-beta.4",
59+
"rollup-plugin-commonjs": "9.1.0",
60+
"rollup-plugin-node-resolve": "3.3.0",
61+
"rollup-plugin-replace": "2.0.0",
62+
"rollup-plugin-uglify": "3.0.0",
63+
"semantic-release": "15.1.7",
64+
"semantic-release-monorepo": "6.0.1",
65+
"typescript": "2.8.3"
66+
},
67+
"keywords": [
68+
"behavior-smooth",
69+
"if-needed",
70+
"polyfill",
71+
"ponyfill",
72+
"scroll",
73+
"scroll-into-view",
74+
"scrollIntoView",
75+
"scrollIntoViewIfNeeded",
76+
"scrollMode",
77+
"smooth",
78+
"smoothscroll",
79+
"typescript"
80+
],
81+
"browserify": {
82+
"transform": ["loose-envify"]
83+
},
84+
"lint-staged": {
85+
"*.js": ["prettier --write", "git add"],
86+
"*.{ts,tsx}": ["prettier --write", "git add"],
87+
"*.json": ["prettier --write", "git add"],
88+
"*.css": ["prettier --write", "git add"],
89+
"*.md": ["prettier --write", "git add"],
90+
"**/package.json": ["prettier-package-json --write", "git add"],
91+
"**/.babelrc": ["prettier --write", "git add"]
92+
},
93+
"module": "es/index.js",
94+
"prettier": {
95+
"semi": false,
96+
"singleQuote": true,
97+
"trailingComma": "es5",
98+
"overrides": [
99+
{
100+
"files": ".babelrc",
101+
"options": {
102+
"parser": "json"
103+
}
104+
}
105+
]
106+
},
107+
"release": {
108+
"prepare": ["@semantic-release/npm"],
109+
"verifyConditions": ["@semantic-release/npm", "@semantic-release/github"]
110+
},
111+
"sideEffects": false,
112+
"typings": "typings/index.d.ts"
113+
}

renovate.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"extends": [
3+
"config:js-lib",
4+
":automergeDigest",
5+
":automergeMinor",
6+
":automergeRequireAllStatusChecks",
7+
":prHourlyLimit4",
8+
":semanticCommits",
9+
":pinDigestsDisabled"
10+
],
11+
"devDependencies": {
12+
"extends": ":automergeMajor"
13+
}
14+
}

rollup.config.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import babel from 'rollup-plugin-babel'
2+
import uglify from 'rollup-plugin-uglify'
3+
import replace from 'rollup-plugin-replace'
4+
import commonjs from 'rollup-plugin-commonjs'
5+
import resolve from 'rollup-plugin-node-resolve'
6+
7+
const config = {
8+
input: 'src/index.ts',
9+
name: 'scrollIntoView',
10+
plugins: [
11+
babel({
12+
exclude: 'node_modules/**',
13+
}),
14+
resolve({
15+
extensions: ['.ts', '.js', '.json'],
16+
}),
17+
commonjs({
18+
include: /node_modules/,
19+
}),
20+
replace({
21+
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
22+
}),
23+
],
24+
}
25+
26+
if (process.env.NODE_ENV === 'production') {
27+
config.plugins.push(uglify())
28+
}
29+
30+
export default config

src/index.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import scrollIntoView from 'scroll-into-view-if-needed'
2+
import { Options } from 'scroll-into-view-if-needed/compute'
3+
4+
// Memoize so we're much more friendly to non-dom envs
5+
let memoizedNow
6+
var now = () => {
7+
if (!memoizedNow) {
8+
memoizedNow =
9+
'performance' in window ? performance.now.bind(performance) : Date.now
10+
}
11+
return memoizedNow()
12+
}
13+
14+
const SCROLL_TIME = 300
15+
16+
function ease(k) {
17+
return 0.5 * (1 - Math.cos(Math.PI * k))
18+
}
19+
20+
function step(context) {
21+
var time = now()
22+
var value
23+
var currentX
24+
var currentY
25+
var elapsed = (time - context.startTime) / SCROLL_TIME
26+
27+
// avoid elapsed times higher than one
28+
elapsed = elapsed > 1 ? 1 : elapsed
29+
30+
// apply easing to elapsed time
31+
value = ease(elapsed)
32+
33+
currentX = context.startX + (context.x - context.startX) * value
34+
currentY = context.startY + (context.y - context.startY) * value
35+
36+
context.method.call(context.scrollable, currentX, currentY)
37+
38+
// scroll more if we have not reached our destination
39+
if (currentX !== context.x || currentY !== context.y) {
40+
requestAnimationFrame(step.bind(global, context))
41+
}
42+
}
43+
44+
function smoothScroll(el, x, y, cb) {
45+
var scrollable
46+
var startX
47+
var startY
48+
var method
49+
var startTime = now()
50+
51+
// define scroll context
52+
if (el === document.body || (el === document.documentElement && true)) {
53+
scrollable = window
54+
startX = window.scrollX || window.pageXOffset
55+
startY = window.scrollY || window.pageYOffset
56+
method = window.scroll
57+
} else {
58+
scrollable = el
59+
startX = el.scrollLeft
60+
startY = el.scrollTop
61+
method = (x, y) => {
62+
el.scrollLeft = x
63+
el.scrollTop = y
64+
}
65+
}
66+
67+
// scroll looping over a frame
68+
step({
69+
scrollable: scrollable,
70+
method: method,
71+
startTime: startTime,
72+
startX: startX,
73+
startY: startY,
74+
x: x,
75+
y: y,
76+
cb,
77+
})
78+
}
79+
80+
export default (target, options: Options = {}) => {
81+
const { behavior = 'smooth' } = options
82+
//return target.scrollIntoView(options)
83+
84+
// @TODO detect if someone is using this library without smooth behavior and maybe warn
85+
if (behavior !== 'smooth') {
86+
return scrollIntoView(target, options)
87+
}
88+
89+
return scrollIntoView(target, {
90+
...options,
91+
behavior: instructions => {
92+
return Promise.all(
93+
instructions.map(({ el, left, top }) => {
94+
return new Promise(resolve => {
95+
smoothScroll(el, left, top, () => resolve())
96+
})
97+
})
98+
)
99+
},
100+
})
101+
}

tsconfig.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es5",
4+
"module": "es2015",
5+
"moduleResolution": "node",
6+
"declaration": true,
7+
"rootDir": "src",
8+
"declarationDir": "typings",
9+
"noImplicitReturns": true,
10+
"noFallthroughCasesInSwitch": true,
11+
"strictNullChecks": true,
12+
"skipLibCheck": true,
13+
"noUnusedLocals": true,
14+
"noUnusedParameters": true,
15+
16+
"alwaysStrict": true,
17+
"lib": ["es5", "es2015.promise", "dom"]
18+
},
19+
"exclude": ["dist", "example", "**/*-test.ts", "cypress"]
20+
}

0 commit comments

Comments
 (0)