├── .editorconfig
├── .env.sample
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .prettierignore
├── .prettierrc.json
├── .release-it.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── commitlint.config.js
├── husky.sh
├── lib
├── @types
│ ├── custom.d.ts
│ └── locomotive-scroll.d.ts
├── LocomotiveScroll.context.tsx
├── index.tsx
└── useLocomotiveScroll.hook.tsx
├── package.json
├── tsconfig.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = false
9 | insert_final_newline = false
10 |
11 | [*.{php,conf}]
12 | indent_style = space
13 | indent_size = 4
14 | end_of_line = lf
15 | charset = utf-8
16 | trim_trailing_whitespace = false
17 | insert_final_newline = false
18 |
--------------------------------------------------------------------------------
/.env.sample:
--------------------------------------------------------------------------------
1 | HUSKY_SKIP_HOOKS=1
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/node_modules/*
2 | **/dist/*
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "plugins": ["@typescript-eslint"],
4 | "extends": [
5 | "eslint:recommended",
6 | "plugin:@typescript-eslint/recommended",
7 | "prettier",
8 | "prettier/@typescript-eslint"
9 | ],
10 | "env": {
11 | "es6": true,
12 | "jest": true,
13 | "node": true
14 | },
15 | "rules": {
16 | "@typescript-eslint/triple-slash-reference": 0,
17 | "@typescript-eslint/explicit-function-return-type": 0,
18 | "@typescript-eslint/explicit-module-boundary-types": 0,
19 | "@typescript-eslint/explicit-member-accessibility": 0,
20 | "@typescript-eslint/indent": 0,
21 | "@typescript-eslint/member-delimiter-style": 0,
22 | "@typescript-eslint/no-non-null-assertion": 0,
23 | "@typescript-eslint/no-explicit-any": 1,
24 | "@typescript-eslint/no-var-requires": 1,
25 | "@typescript-eslint/no-use-before-define": 0,
26 | "@typescript-eslint/ban-ts-comment": 0,
27 | "@typescript-eslint/no-empty-function": [
28 | 2,
29 | {
30 | "allow": ["arrowFunctions"]
31 | }
32 | ],
33 | "@typescript-eslint/no-unused-vars": [
34 | 2,
35 | {
36 | "argsIgnorePattern": "^_"
37 | }
38 | ],
39 | "no-console": [
40 | 2,
41 | {
42 | "allow": ["warn", "error"]
43 | }
44 | ]
45 | },
46 | "overrides": [{
47 | "files": ["*.js"],
48 | "rules": {
49 | "@typescript-eslint/no-var-requires": "off"
50 | }
51 | }]
52 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
106 | .DS_Store
107 |
108 | module/
109 | .husky
110 | .DS_Store
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/node_modules/*
2 | **/module/*
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "typescript",
3 | "printWidth": 100,
4 | "tabWidth": 2,
5 | "semi": false,
6 | "singleQuote": true,
7 | "trailingComma": "es5",
8 | "bracketSpacing": true,
9 | "jsxBracketSameLine": false,
10 | "arrowParens": "avoid"
11 | }
12 |
--------------------------------------------------------------------------------
/.release-it.json:
--------------------------------------------------------------------------------
1 | {
2 | "git": {
3 | "requireBranch": "main",
4 | "requireCommits": true,
5 | "requireCleanWorkingDir": false,
6 | "addFiles": ["package.json", "CHANGELOG.md"]
7 | },
8 | "npm": {
9 | "publish": true
10 | },
11 | "github": {
12 | "release": true
13 | },
14 | "plugins": {
15 | "@release-it/conventional-changelog": {
16 | "preset": "angular",
17 | "infile": "CHANGELOG.md"
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## [0.2.2](https://github.com/toinelin/react-locomotive-scroll/compare/0.2.1...0.2.2) (2022-07-22)
4 |
5 |
6 | ### Bug Fixes
7 |
8 | * pre-release command ([a12b653](https://github.com/toinelin/react-locomotive-scroll/commit/a12b653b2f24b6a01f81ef4b25038c25cc6ba6d7))
9 |
10 | ## [0.2.1](https://github.com/toinelin/react-locomotive-scroll/compare/0.2.0...0.2.1) (2022-07-22)
11 |
12 | # [0.2.0](https://github.com/toinelin/react-locomotive-scroll/compare/0.1.8...0.2.0) (2021-09-13)
13 |
14 |
15 | ### Bug Fixes
16 |
17 | * **update-react-version:** update React version from 17.0.1 to ^17.0.2 ([bd77ddd](https://github.com/toinelin/react-locomotive-scroll/commit/bd77ddd3540563f5f548019014314566fda3a671)), closes [#14](https://github.com/toinelin/react-locomotive-scroll/issues/14)
18 |
19 |
20 | ### Features
21 |
22 | * **provider:** add onUpdate, location and onLocationChange props ([83ffcfd](https://github.com/toinelin/react-locomotive-scroll/commit/83ffcfd529edaeac27b03fbb6825bcf29d5a64a2)), closes [#9](https://github.com/toinelin/react-locomotive-scroll/issues/9)
23 |
24 |
25 | ### Reverts
26 |
27 | * **package-verison:** removes package version bump ([773087f](https://github.com/toinelin/react-locomotive-scroll/commit/773087ff872d7df2d10107355f870b88aa59e880))
28 |
29 | ## [0.1.8](https://github.com/toinelin/react-locomotive-scroll/compare/0.1.7...0.1.8) (2021-04-30)
30 |
31 | ## [0.1.7](https://github.com/toinelin/react-locomotive-scroll/compare/0.1.6...0.1.7) (2021-02-19)
32 |
33 |
34 | ### Reverts
35 |
36 | * **build:** add tslib to paths + re-use target es2015 ([4eeb853](https://github.com/toinelin/react-locomotive-scroll/commit/4eeb853efabed59fe923aaba710bca124b4633b9))
37 |
38 | ## [0.1.6](https://github.com/toinelin/react-locomotive-scroll/compare/0.1.5...0.1.6) (2021-02-19)
39 |
40 |
41 | ### Reverts
42 |
43 | * **tsconfig:** revert module to commonjs ([f2f83f6](https://github.com/toinelin/react-locomotive-scroll/commit/f2f83f60b5622804d862e4522114da2bf96c1de4))
44 |
45 | ## [0.1.5](https://github.com/toinelin/react-locomotive-scroll/compare/0.1.4...0.1.5) (2021-02-19)
46 |
47 | ## [0.1.4](https://github.com/toinelin/react-locomotive-scroll/compare/0.1.3...0.1.4) (2021-02-19)
48 |
49 | ## [0.1.3](https://github.com/toinelin/react-locomotive-scroll/compare/0.1.2...0.1.3) (2021-02-19)
50 |
51 | ## [0.1.2](https://github.com/toinelin/react-locomotive-scroll/compare/0.1.1...0.1.2) (2021-02-09)
52 |
53 | # 0.1.1 (2021-02-09)
54 |
55 |
56 | ### Reverts
57 |
58 | * **use-resize-observer:** finaly force the use of observer to avoid weird behaviours ([3ac0e7e](https://github.com/toinelin/react-locomotive-scroll/commit/3ac0e7eee2d28a0613fa958fdba80f254d8f9c30))
59 |
60 | # 0.1.0 (2021-02-09)
61 |
62 |
63 | ### Bug Fixes
64 |
65 | * **deps:** move use-resize-observer to devDeps ([0826448](https://github.com/toinelin/react-locomotive-scroll/commit/0826448c608b1fb96ea701d3f470ed3b5cc048b7))
66 |
67 |
68 | ### Features
69 |
70 | * **context + hook:** add context, hook and release deps ([d01e09a](https://github.com/toinelin/react-locomotive-scroll/commit/d01e09a4b03a02a8165e788a6d70cf9e3da5f4f5))
71 |
72 |
73 | ### Reverts
74 |
75 | * **use-resize-observer:** finaly force the use of observer to avoid weird behaviours ([3ac0e7e](https://github.com/toinelin/react-locomotive-scroll/commit/3ac0e7eee2d28a0613fa958fdba80f254d8f9c30))
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Antoine LIN
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
React Locomotive Scroll
10 |
11 |
12 | A locomotive-scroll React wrapper
13 |
14 | Explore Locomotive Scroll docs »
15 |
16 |
17 |
19 | Report Bug
20 | ·
21 | Request Feature
22 |
23 |
24 |
25 |
26 |
27 |
28 | Table of Contents
29 |
30 | -
31 | Getting Started
32 |
36 |
37 | - Usage
38 | - Specific cases
39 | - Contributing
40 | - License
41 | - Contact
42 | - Acknowledgements
43 |
44 |
45 | ## Getting Started
46 |
47 | To get a local copy up and running follow these simple steps.
48 |
49 | ### Installation
50 |
51 | ```sh
52 | $ npm install locomotive-scroll react-locomotive-scroll
53 | ```
54 |
55 | or using [Yarn](https://yarnpkg.com/)
56 |
57 | ```sh
58 | $ yarn add locomotive-scroll react-locomotive-scroll
59 | ```
60 |
61 |
62 |
63 |
64 | ## Usage
65 |
66 | ### 1. Import the provider
67 | ```js
68 | import { LocomotiveScrollProvider } from 'react-locomotive-scroll'
69 | ```
70 |
71 | ### 2. Wrap your application using the provider
72 | ```js
73 | const containerRef = useRef(null)
74 |
75 |
91 |
92 | {/* ...your app */}
93 |
94 |
95 | ```
96 |
97 | ### 3. Wrap your pages using `data-scroll-section` to prevent weird behaviours
98 |
99 | ```js
100 | export function Page() {
101 | return (
102 |
103 | {/* ...your page */}
104 |
105 | )
106 | }
107 | ```
108 |
109 | From the Locomotive Scroll doc : `Defines a scrollable section. Splitting your page into sections may improve performance.`
110 | You may want to use `data-scroll-section` on each page which may be wrapped by `LocomotiveScrollProvider`
111 |
112 | ### 4. Add the base styles to your CSS file.
113 |
114 | [`locomotive-scroll.css`](https://github.com/locomotivemtl/locomotive-scroll/blob/master/dist/locomotive-scroll.css)
115 |
116 | ### 5. Get the scroll instance through all your components
117 | ```js
118 | import { useLocomotiveScroll } from 'react-locomotive-scroll'
119 |
120 | export function Component() {
121 | const { scroll } = useLocomotiveScroll()
122 |
123 | // ... your component
124 | }
125 | ```
126 |
127 | At this time you should be able to do whatever your want using the scroll object.
128 |
129 | For more examples and to use Locomotive Scroll, please refer to their [Documentation](https://github.com/locomotivemtl/locomotive-scroll)
130 |
131 | ## Specific cases
132 |
133 | ### 1. Apply code to the location update only
134 |
135 | If you want to write some code applied only when the location change but not when the rest of your dependencies added to the `watch` list change, here the thing:
136 |
137 | First, remove the location props from the `watch` dependencies list and add it to the `location` props.
138 |
139 | > `react-locomotive-scroll` will update the scroll instance as it should, but in a different `useEffect` than the one used to update watched dependencies
140 |
141 | ```js
142 | const { pathname } = useLocation() // With react-router
143 | const { asPath } = useRouter() // With next/router
144 |
145 | scroll.scrollTo(0, { duration: 0, disableLerp: true })} // If you want to reset the scroll position to 0 for example
160 | onUpdate={() => console.log('Updated, but not on location change!')} // Will trigger on
161 | >
162 |
163 | {/* ...your app */}
164 |
165 |
166 | ```
167 |
168 |
169 | ## Troubleshooting
170 |
171 | - [Flickering on Google Chrome v94](https://github.com/locomotivemtl/locomotive-scroll/issues/353)
172 |
173 |
174 | ## Contributing
175 |
176 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
177 |
178 | 1. Fork the Project
179 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
180 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
181 | 4. Push to the Branch (`git push origin feature/AmazingFeature`)
182 | 5. Open a Pull Request
183 |
184 |
185 |
186 | ## License
187 |
188 | Distributed under the MIT License. See `LICENSE` for more information.
189 |
190 |
191 |
192 |
193 | ## Contact
194 |
195 | Antoine Lin - [@vahilloff](https://twitter.com/vahilloff) - contact@antoinelin.com
196 |
197 | Project Link: [https://github.com/toinelin/react-locomotive-scroll](https://github.com/toinelin/react-locomotive-scroll)
198 |
199 |
200 |
201 |
202 | ## Acknowledgements
203 |
204 | * []()
205 | * []()
206 | * []()
207 |
208 | _Please feel free to open a pull request to add your project to the list!_
209 |
210 |
211 |
212 |
213 |
214 |
215 | [contributors-shield]: https://img.shields.io/github/contributors/toinelin/repo.svg?style=for-the-badge
216 | [contributors-url]: https://github.com/toinelin/repo/graphs/contributors
217 | [forks-shield]: https://img.shields.io/github/forks/toinelin/repo.svg?style=for-the-badge
218 | [forks-url]: https://github.com/toinelin/repo/network/members
219 | [stars-shield]: https://img.shields.io/github/stars/toinelin/repo.svg?style=for-the-badge
220 | [stars-url]: https://github.com/toinelin/repo/stargazers
221 | [issues-shield]: https://img.shields.io/github/issues/toinelin/repo.svg?style=for-the-badge
222 | [issues-url]: https://github.com/toinelin/repo/issues
223 | [license-shield]: https://img.shields.io/github/license/toinelin/repo.svg?style=for-the-badge
224 | [license-url]: https://github.com/toinelin/repo/blob/master/LICENSE.txt
225 | [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
226 | [linkedin-url]: https://linkedin.com/in/toinelin
227 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['@commitlint/config-conventional'],
3 | }
4 |
--------------------------------------------------------------------------------
/husky.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | npx husky add .husky/pre-commit "yarn pre-commit"
3 | npx husky add .husky/prepare-commit-msg "yarn prepare-commit-msg"
--------------------------------------------------------------------------------
/lib/@types/custom.d.ts:
--------------------------------------------------------------------------------
1 | type WithChildren> = T & { children?: React.ReactNode }
2 |
--------------------------------------------------------------------------------
/lib/@types/locomotive-scroll.d.ts:
--------------------------------------------------------------------------------
1 | // Credits: https://github.com/locomotivemtl/locomotive-scroll/pull/38/commits/8a112a4ec21fa7262372123262e15a82ddf053b7
2 |
3 | declare module 'locomotive-scroll' {
4 | export function getParents(elem: Element): Element[]
5 | export function queryClosestParent(elem: Element, selector: string): Element | null
6 | export function transform(el: Element, transformValue: string): void
7 | export function getTranslate(el: Element): Vector2
8 | export function lerp(start: number, end: number, amt: number)
9 |
10 | export type Vector2 = {
11 | x: number
12 | y: number
13 | }
14 |
15 | export type LocomotiveElementAttributes = {
16 | el: HTMLElement
17 | class: string
18 | top: number
19 | bottom: number
20 | offset: number
21 | repeat: boolean
22 | inView: boolean
23 | call: string
24 | }
25 |
26 | export type ScrollInstance = {
27 | scroll: Vector2
28 | limit: number
29 | }
30 |
31 | export class Core implements LocomotiveScrollOptions {
32 | el?: Element
33 | elMobile?: Element
34 | name?: string
35 | offset?: number
36 | repeat?: boolean
37 | smooth?: boolean
38 | smoothMobile?: boolean
39 | direction?: string
40 | inertia?: number
41 | class?: string
42 | scrollbarClass?: string
43 | scrollingClass?: string
44 | draggingClass?: string
45 | smoothClass?: string
46 | initClass?: string
47 | getSpeed?: boolean
48 | getDirection?: boolean
49 |
50 | namespace: string
51 | html: Element
52 | windowHeight: number
53 | windowMiddle: number
54 | els: Element[]
55 | hasScrollTicking: boolean
56 | hasCallEventSet: boolean
57 | instance: ScrollInstance
58 |
59 | constructor(options?: LocomotiveScrollOptions)
60 |
61 | init(): void
62 | checkScroll(): void
63 | checkResize(): void
64 | initEvents(): void
65 | setScrollTo(event: Event): void
66 | addElements(): void
67 | detectElements(hasCallEventSet: boolean): void
68 | setInView(current: LocomotiveElementAttributes, i: number): void
69 | setOutOfView(current: LocomotiveElementAttributes, i: number): void
70 | dispatchCall(current: LocomotiveElementAttributes, way: string): void
71 | dispatchScroll(): void
72 | setEvents(event: string, func: string | string[]): void
73 | startScroll(): void
74 | stopScroll(): void
75 | setScroll(x: number, y: number): void
76 | destroy(): void
77 | }
78 |
79 | export class Native extends Core {
80 | constructor(options?: LocomotiveScrollOptions)
81 |
82 | init(): void
83 | checkScroll(): void
84 | checkResize(): void
85 | addElements(): void
86 | updateElements(): void
87 | scrollTo(targetOption: string | Event, offsetOption: number): void
88 | update(): void
89 | destroy(): void
90 | }
91 |
92 | export class Smooth extends Core {
93 | isScrolling: boolean
94 | isDraggingScrollbar: boolean
95 | isTicking: boolean
96 | parallaxElements: Element[]
97 | inertiaRatio: number
98 | stop: boolean
99 |
100 | constructor(options?: LocomotiveScrollOptions)
101 |
102 | init(): void
103 | setScrollLimit(): void
104 | startScrolling(): void
105 | stopScrolling(): void
106 | checkKey(e: KeyboardEvent): void
107 | checkScroll(): void
108 | checkResize(): void
109 | updateDelta(e: WheelEvent): void
110 | updateScroll(e: Event): void
111 | addDirection(): void
112 | addSpeed(): void
113 | initScrollBar(): void
114 | reinitScrollBar(): void
115 | destroyScrollBar(): void
116 | getScrollBar(e: Event): void
117 | releaseScrollBar(e: Event): void
118 | moveScrollBar(e: MouseEvent): void
119 | addElements(): void
120 | addSections(): void
121 | transform(element: Element, x: number, y: number, delay: number): void
122 | transformElement(isForced: boolean): void
123 | scrollTo(targetOption: string | Event, offsetOption: number): void
124 | update(): void
125 | startScroll(): void
126 | stopScroll(): void
127 | setScroll(x: number, y: number): void
128 | destroy(): void
129 | }
130 |
131 | export interface LocomotiveScrollOptions {
132 | el?: Element
133 | elMobile?: Element
134 | name?: string
135 | offset?: number
136 | repeat?: boolean
137 | smooth?: boolean
138 | smoothMobile?: boolean
139 | direction?: string
140 | inertia?: number
141 | class?: string
142 | scrollbarClass?: string
143 | scrollingClass?: string
144 | draggingClass?: string
145 | smoothClass?: string
146 | initClass?: string
147 | getSpeed?: boolean
148 | getDirection?: boolean
149 | }
150 |
151 | export default class LocomotiveScroll implements LocomotiveScrollOptions {
152 | el?: Element
153 | elMobile?: Element
154 | name?: string
155 | offset?: number
156 | repeat?: boolean
157 | smooth?: boolean
158 | smoothMobile?: boolean
159 | direction?: string
160 | inertia?: number
161 | class?: string
162 | scrollbarClass?: string
163 | scrollingClass?: string
164 | draggingClass?: string
165 | smoothClass?: string
166 | initClass?: string
167 | getSpeed?: boolean
168 | getDirection?: boolean
169 |
170 | isMobile: boolean
171 | options: LocomotiveScrollOptions
172 | scroll: Smooth | Native
173 |
174 | constructor(options?: LocomotiveScrollOptions)
175 |
176 | init(): void
177 | update(): void
178 | start(): void
179 | stop(): void
180 | scrollTo(
181 | target: Node | string | number,
182 | options: {
183 | offset?: number
184 | callback?: () => void
185 | duration?: number
186 | easing?: [number, number, number, number]
187 | disableLerp?: boolean
188 | }
189 | ): void
190 | setScroll(x: number, y: number): void
191 | on(event: 'call' | 'scroll', func: (data: string | string[]) => void): void
192 | destroy(): void
193 | }
194 |
195 | export { LocomotiveScroll as Scroll }
196 | }
197 |
--------------------------------------------------------------------------------
/lib/LocomotiveScroll.context.tsx:
--------------------------------------------------------------------------------
1 | import { LocomotiveScrollOptions, Scroll } from 'locomotive-scroll'
2 | import { createContext, DependencyList, MutableRefObject, useEffect, useRef, useState } from 'react'
3 | import { useDebounce } from 'use-debounce'
4 | import useResizeObserver from 'use-resize-observer'
5 |
6 | export interface LocomotiveScrollContextValue {
7 | scroll: Scroll | null
8 | isReady: boolean
9 | }
10 |
11 | export const LocomotiveScrollContext = createContext({
12 | scroll: null,
13 | isReady: false,
14 | })
15 |
16 | export interface LocomotiveScrollProviderProps {
17 | options: LocomotiveScrollOptions
18 | containerRef: MutableRefObject
19 | watch: DependencyList | undefined
20 | onUpdate?: (scroll: Scroll) => void
21 | location?: string
22 | onLocationChange?: (scroll: Scroll) => void
23 | }
24 |
25 | export function LocomotiveScrollProvider({
26 | children,
27 | options,
28 | containerRef,
29 | watch,
30 | onUpdate,
31 | location,
32 | onLocationChange,
33 | }: WithChildren) {
34 | const { height: containerHeight } = useResizeObserver({ ref: containerRef })
35 | const [isReady, setIsReady] = useState(false)
36 | const LocomotiveScrollRef = useRef(null)
37 | const [height] = useDebounce(containerHeight, 100)
38 |
39 | if (!watch) {
40 | console.warn(
41 | 'react-locomotive-scroll: you did not add any props to watch. Scroll may have weird behaviours if the instance is not updated when the route changes'
42 | )
43 | }
44 |
45 | useEffect(() => {
46 | ;(async () => {
47 | try {
48 | const LocomotiveScroll = (await import('locomotive-scroll')).default
49 |
50 | const dataScrollContainer = document.querySelector('[data-scroll-container]')
51 |
52 | if (!dataScrollContainer) {
53 | console.warn(
54 | `react-locomotive-scroll: [data-scroll-container] dataset was not found. You likely forgot to add it which will prevent Locomotive Scroll to work.`
55 | )
56 | }
57 |
58 | LocomotiveScrollRef.current = new LocomotiveScroll({
59 | el: dataScrollContainer ?? undefined,
60 | ...options,
61 | })
62 |
63 | setIsReady(true) // Re-render the context
64 | } catch (error) {
65 | throw Error(`react-locomotive-scroll: ${error}`)
66 | }
67 | })()
68 |
69 | return () => {
70 | LocomotiveScrollRef.current?.destroy()
71 | setIsReady(false)
72 | }
73 | }, [])
74 |
75 | useEffect(
76 | () => {
77 | if (!LocomotiveScrollRef.current) {
78 | return
79 | }
80 |
81 | LocomotiveScrollRef.current.update()
82 |
83 | if (onUpdate) {
84 | onUpdate(LocomotiveScrollRef.current)
85 | }
86 | },
87 | watch ? [...watch, height] : [height]
88 | )
89 |
90 | useEffect(() => {
91 | if (!LocomotiveScrollRef.current || !location) {
92 | return
93 | }
94 |
95 | LocomotiveScrollRef.current.update()
96 |
97 | if (onLocationChange) {
98 | onLocationChange(LocomotiveScrollRef.current)
99 | }
100 | }, [location])
101 |
102 | return (
103 |
104 | {children}
105 |
106 | )
107 | }
108 |
109 | LocomotiveScrollContext.displayName = 'LocomotiveScrollContext'
110 | LocomotiveScrollProvider.displayName = 'LocomotiveScrollProvider'
111 |
--------------------------------------------------------------------------------
/lib/index.tsx:
--------------------------------------------------------------------------------
1 | export type { LocomotiveScrollOptions, Scroll, ScrollInstance } from 'locomotive-scroll'
2 | export { LocomotiveScrollContext, LocomotiveScrollProvider } from './LocomotiveScroll.context'
3 | export type {
4 | LocomotiveScrollContextValue,
5 | LocomotiveScrollProviderProps,
6 | } from './LocomotiveScroll.context'
7 | export { useLocomotiveScroll } from './useLocomotiveScroll.hook'
8 |
--------------------------------------------------------------------------------
/lib/useLocomotiveScroll.hook.tsx:
--------------------------------------------------------------------------------
1 | import { useContext, useEffect } from 'react'
2 | import { LocomotiveScrollContext, LocomotiveScrollContextValue } from './LocomotiveScroll.context'
3 |
4 | export function useLocomotiveScroll(): LocomotiveScrollContextValue {
5 | const context = useContext(LocomotiveScrollContext)
6 |
7 | if (context === undefined) {
8 | console.warn(
9 | 'react-locomotive-scroll: the context is missing. You may be using the hook without registering LocomotiveScrollProvider, or you may be using the hook in a component which is not wrapped by LocomotiveScrollProvider.'
10 | )
11 | }
12 |
13 | return context
14 | }
15 |
16 | useLocomotiveScroll.displayName = 'useLocomotiveScroll'
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-locomotive-scroll",
3 | "version": "0.2.2",
4 | "description": "A locomotive-scroll React wrapper",
5 | "main": "module/index.js",
6 | "module": "module/index.js",
7 | "typings": "module/index.d.ts",
8 | "repository": "git@github.com:toinelin/react-locomotive-scroll.git",
9 | "author": "Antoine ",
10 | "license": "MIT",
11 | "keywords": [
12 | "react",
13 | "locomotive-scroll",
14 | "smooth-scroll",
15 | "typescript"
16 | ],
17 | "files": [
18 | "lib",
19 | "module"
20 | ],
21 | "scripts": {
22 | "build": "rm -rf ./module && tsc",
23 | "lint": "eslint --quiet",
24 | "format": "prettier --debug-check lib/**/*.{ts,tsx}",
25 | "prepare:husky": "husky install && sh ./husky.sh",
26 | "prepare": "yarn prepare:husky && yarn lint && yarn format && yarn build",
27 | "pre-commit": "yarn lint && yarn format && lint-staged",
28 | "prepare-commit-msg": "exec < /dev/tty && git cz --hook || true",
29 | "release": "dotenv release-it --",
30 | "pre-release": "dotenv release-it major --preRelease=beta --"
31 | },
32 | "config": {
33 | "commitizen": {
34 | "path": "cz-conventional-changelog"
35 | }
36 | },
37 | "lint-staged": {
38 | "lib/**/*.{ts,tsx,js,jsx,md}": [
39 | "eslint --quiet",
40 | "prettier --write"
41 | ]
42 | },
43 | "dependencies": {
44 | "use-debounce": "6.0.1",
45 | "use-resize-observer": "6.1.0"
46 | },
47 | "devDependencies": {
48 | "@release-it/conventional-changelog": "5.0.0",
49 | "@types/react": "17.0.1",
50 | "@typescript-eslint/eslint-plugin": "4.14.2",
51 | "@typescript-eslint/parser": "4.14.2",
52 | "commitizen": "4.2.3",
53 | "dotenv-cli": "6.0.0",
54 | "eslint": "7.19.0",
55 | "eslint-config-prettier": "7.2.0",
56 | "husky": "8.0.1",
57 | "lint-staged": "13.0.3",
58 | "prettier": "2.2.1",
59 | "prettier-plugin-organize-imports": "1.1.1",
60 | "release-it": "15.1.3",
61 | "typescript": "4.7.4"
62 | },
63 | "peerDependencies": {
64 | "locomotive-scroll": "^4.1.4",
65 | "react": "^18.0.2"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "compilerOptions": {
4 | "outDir": "./module",
5 | "sourceMap": false,
6 | "declaration": true,
7 | "strict": true,
8 | "noUnusedLocals": false,
9 | "skipLibCheck": true,
10 | "allowJs": true,
11 | "allowSyntheticDefaultImports": true,
12 | "removeComments": false,
13 | "esModuleInterop": true,
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "module": "CommonJS",
17 | "moduleResolution": "Node",
18 | "target": "ES2015",
19 | "importHelpers": true,
20 | "jsx": "react-jsx",
21 | "lib": [
22 | "DOM",
23 | "ESNext"
24 | ],
25 | "typeRoots" : [
26 | "./node_modules/@types",
27 | "./lib/@types"
28 | ],
29 | "baseUrl": ".",
30 | "paths": {
31 | "*": ["*"],
32 | "tslib": ["node_modules/tslib"]
33 | }
34 | },
35 | "include": [
36 | "./lib/**/*"
37 | , "@types" ],
38 | "exclude": [
39 | "./module",
40 | "node_modules"
41 | ]
42 | }
--------------------------------------------------------------------------------