Skip to content

Commit 3a0f69e

Browse files
authored
Merge pull request #9 from theKashey/sidecar
sidecar
2 parents 941290c + 0ecaafa commit 3a0f69e

35 files changed

+5440
-1148
lines changed

.size-limit

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
[
22
{
33
path: "dist/es2015/index.js",
4-
ignore: ["react-dom", "tslib"],
5-
limit: "2.1 KB"
4+
ignore: ["react-dom", "tslib", "use-sidecar"],
5+
limit: "2.0 KB"
6+
},
7+
{
8+
path: "dist/es2015/sidecar.js",
9+
ignore: ["react-dom", "tslib", "use-sidecar"],
10+
limit: "1.5 KB"
11+
},
12+
{
13+
path: "dist/es2015/UI.js",
14+
ignore: ["react-dom", "tslib", "use-sidecar"],
15+
limit: "0.5 KB"
616
}
717
]

.storybook/addons.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import '@storybook/addon-actions/register';
2+
import '@storybook/addon-links/register';

.storybook/config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { configure } from '@storybook/react';
2+
3+
// automatically import all files ending in *.stories.js
4+
const req = require.context('../stories', true, /\.stories\.js$/);
5+
function loadStories() {
6+
req.keys().forEach(filename => req(filename));
7+
}
8+
9+
configure(loadStories, module);

.storybook/webpack.config.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module.exports = ({ config }) => {
2+
config.mode = 'production';
3+
config.module.rules.push({
4+
test: /\.(ts|tsx)$/,
5+
use: [
6+
{
7+
loader: require.resolve('jsx-compress-loader'),
8+
},
9+
{
10+
loader: require.resolve('awesome-typescript-loader'),
11+
},
12+
],
13+
});
14+
config.resolve.extensions.push('.ts', '.tsx');
15+
return config;
16+
};

README.md

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,39 @@
1+
<div align="center">
2+
<h1>React-remove-📜</h1>
3+
<br/>
4+
dont even scroll
5+
<br/>
6+
7+
<a href="https://www.npmjs.com/package/react-remove-scroll">
8+
<img src="https://img.shields.io/npm/v/react-remove-scroll.svg?style=flat-square" />
9+
</a>
10+
11+
<a href="https://travis-ci.org/theKashey/react-remove-scroll">
12+
<img src="https://img.shields.io/travis/theKashey/react-remove-scroll.svg?style=flat-square" alt="Build status">
13+
</a>
14+
15+
<a href="https://www.npmjs.com/package/react-remove-scroll">
16+
<img src="https://img.shields.io/npm/dm/react-remove-scroll.svg" alt="npm downloads">
17+
</a>
18+
19+
<a href="https://bundlephobia.com/result?p=react-remove-scroll">
20+
<img src="https://img.shields.io/bundlephobia/minzip/react-remove-scroll.svg" alt="bundle size">
21+
</a>
22+
<br/>
23+
</div>
24+
125
react-remove-scroll
226
====
327
[![NPM version](https://img.shields.io/npm/v/react-remove-scroll.svg)](https://www.npmjs.com/package/react-remove-scroll)
428

529
Disables scroll outside of `children` node.
630

731
- 🖱 mouse and touch devices friendly
32+
- 📈 vertical and horizontal
833
- 📜 removes document scroll bar maintaining it space
934
- ✅ support nested scrollable elements
1035
- 🕳 supports react-portals (uses React Event system)
36+
- ☠️ it could block literally any scroll anywhere
1137

1238
# Usage
1339
Just wrap content, which should be scrollable, and everything else would not.
@@ -22,10 +48,31 @@ import {RemoveScroll} from 'react-remove-scroll';
2248
`RemoveScroll` accept following props
2349
- `children`
2450
- `[enabled]` - activate or deactivate component behaviour without removing it.
25-
- `[noIsolation]` - disables outer event capturing
51+
- `[noIsolation=false]` - disables outer event capturing. Event capturing is React friendly and unlikely be a problem.
52+
But if you are using _shadowbox_ of some sort - you dont need it.
53+
- `[inert=false]` - ☠️(be careful) disables events the rest of page completely using `pointer-events` expect the Lock(+shard).
54+
React portals not friendly, might lead to production issues. Enable only for __rare__ cases, when you have to disable scrollbars somewhere on the page(except body, Lock and shards).
2655
- `[forwardProps]` - will forward all props to the `children`
2756
- `[className]` - className for an internal div
28-
- `[removeScrollBar]` - to control scroll bar removal. Set to false, if you prefer to keep it (wheel and touch scroll still disabled).
57+
- `[removeScrollBar]` - to control scroll bar removal. Set to false, if you prefer to keep it (wheel and touch scroll is still disabled).
58+
59+
# Size
60+
- (🧩 full) 1.7kb after compression (excluding tslib).
61+
---
62+
- (👁 UI) __400b__, visual elements only
63+
- (🚗 sidecar) 1.5kb, side effects
64+
```js
65+
import {sidecar} from "react-remove-scroll";
66+
import {RemoveScroll} from 'react-remove-scroll/UI';
67+
68+
const sidecar = sidecar(() => import('react-remove-scroll/sidecar'));
69+
70+
<RemoveScroll sideCar={sidecar}>
71+
Will load logic from a sidecar when needed
72+
</RemoveScroll>
73+
```
74+
75+
> Consider setting `-webkit-overflow-scrolling: touch;` on a document level for a proper mobile experience.
2976
3077
## Internal div
3178
But default RemoveScroll will create a div to handle and capture events.
@@ -63,6 +110,18 @@ See [react-remove-scroll-bar](https://github.com/theKashey/react-remove-scroll-b
63110
## More than one lock
64111
When stacked more is active (default) only one (last) component would be active.
65112

113+
## Over isolation
114+
That could happen -
115+
you disable scroll on the body,
116+
you are suppressing all scroll and wheel events,
117+
and you are ghosting the rest of the page by the `inert` prop.
118+
119+
Only something inside Lock does exists for the browser, and that might be less than you expected.
120+
121+
Dont forget about `shard`, dont forget - `inert` is not portals friendly, dont forget - you dont need over isolation in most of the cases.
122+
123+
> just be careful!
124+
66125
# Performance
67126
To do the job this library setup _non_ passive event listener. Chrome dev tools would complain about it, as a
68127
performance no-op.
@@ -71,8 +130,9 @@ We have to use synchronous scroll/touch handler, and it may affect scrolling per
71130

72131
Consider using `noIsolation` mode, if you have large scrollable areas.
73132

74-
# Size
75-
1.5kb after compression (excluding tslib).
133+
# Supported React versions
134+
- v1 supports React 15/16
135+
- v2 requires 16.8.0+ (hooks)
76136

77137
# Scroll-Locky
78138
This is a refactoring of another library - [react-scroll-locky](https://github.com/theKashey/react-scroll-locky) -

UI/UI.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from '../dist/es2015/UI'

UI/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"private": true,
3+
"main": "../dist/cjs/UI.js",
4+
"jsnext:main": "../dist/es2015/UI.js",
5+
"module": "../dist/es2015/UI.js",
6+
"types": "UI.d.ts",
7+
"sideEffects": false
8+
}

__tests__/UI.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as React from 'react';
2+
import {configure, mount} from 'enzyme';
3+
import * as Adapter from 'enzyme-adapter-react-16';
4+
import {RemoveScroll} from '../src/UI';
5+
import {sidecar} from "use-sidecar";
6+
7+
configure({adapter: new Adapter()});
8+
9+
const tick = () => new Promise(resolve => setTimeout(resolve, 10));
10+
11+
const car = sidecar(() => import ('../src/sidecar'));
12+
13+
describe('UI', () => {
14+
it('smoke', async () => {
15+
const wrapper = mount(
16+
<RemoveScroll sideCar={car}>content</RemoveScroll>
17+
);
18+
await tick();
19+
expect(wrapper.html()).toContain('content');
20+
console.log(document.body.className);
21+
});
22+
23+
it('forward', async () => {
24+
const wrapper = mount(
25+
<RemoveScroll sideCar={car} forwardProps>
26+
<div>content</div>
27+
</RemoveScroll>
28+
);
29+
await tick();
30+
expect(wrapper.html()).toContain('content');
31+
console.log(document.body.className);
32+
});
33+
});

__tests__/combination.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as React from 'react';
2+
import {configure, mount} from 'enzyme';
3+
import * as Adapter from 'enzyme-adapter-react-16';
4+
import {RemoveScroll} from '../src';
5+
6+
configure({ adapter: new Adapter() });
7+
8+
const tick = () => new Promise(resolve => setTimeout(resolve, 10));
9+
10+
describe('Endpoint UI', () => {
11+
it('smoke', async () => {
12+
const wrapper = mount(<RemoveScroll>content</RemoveScroll>);
13+
await tick();
14+
expect(wrapper.html()).toContain('content');
15+
console.log(document.body.className);
16+
});
17+
18+
it.only('forward', async () => {
19+
const wrapper = mount(<RemoveScroll forwardProps><div>content</div></RemoveScroll>);
20+
await tick();
21+
expect(wrapper.html()).toContain('content');
22+
console.log(document.body.className);
23+
});
24+
});

__tests__/index.tsx

Lines changed: 0 additions & 14 deletions
This file was deleted.

example/app.tsx

Lines changed: 15 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import * as React from 'react';
22
import * as ReactDOM from 'react-dom';
33
import {Component} from 'react';
4-
import {AppWrapper} from './styled';
5-
import {RemoveScroll} from "../src";
4+
import {RemoveScroll} from "../src/UI";
5+
import {sidecar} from "use-sidecar";
6+
7+
const lockSideCar = sidecar(() => import ("../src/sidecar"));
68

79
export interface AppState {
810
counter: number;
@@ -31,13 +33,14 @@ const PDiv = () => (
3133
}}
3234
// className={zeroRightClassName}
3335
>
36+
<button onClick={() => alert('xxx')}>click me</button>
3437
PORTALED SCROLLABLE
3538
{fill(20, 1).map(x => <p>{x}****</p>)}
3639
</div>
3740
);
3841

3942
const Portal = () => (
40-
ReactDOM.createPortal(<PDiv/>, document.getElementById('portal'))
43+
ReactDOM.createPortal(<PDiv/>, document.getElementById('portal')!)
4144
)
4245

4346
export default class App extends Component <{}, AppState> {
@@ -47,7 +50,7 @@ export default class App extends Component <{}, AppState> {
4750

4851
componentDidMount() {
4952
setInterval(() => {
50-
//this.setState({counter: this.state.counter ? 0 : 1})
53+
//this.setState({counter: this.state.counter ? 0 : 1})
5154
}, 1000);
5255

5356
setTimeout(() => {
@@ -57,7 +60,7 @@ export default class App extends Component <{}, AppState> {
5760

5861
render() {
5962
return (
60-
<AppWrapper>
63+
<div>
6164
<div style={{
6265
position: 'absolute',
6366
left: 0,
@@ -82,7 +85,10 @@ export default class App extends Component <{}, AppState> {
8285
// className={zeroRightClassName}
8386
>
8487
SCROLL (end of content would be hidden under "parent" scroll).
85-
{(<RemoveScroll enabled={true}>
88+
{(<RemoveScroll
89+
enabled={true}
90+
sideCar={lockSideCar}
91+
>
8692
<div
8793
style={{
8894
//position: 'absolute',
@@ -95,7 +101,7 @@ export default class App extends Component <{}, AppState> {
95101
color: '#FFF',
96102
backgroundColor: 'rgba(0,0,0,0.5)'
97103
}}
98-
// className={zeroRightClassName}
104+
// className={RemoveScroll.classNames.zeroRight}
99105
>
100106
PRIMARY SCROLLABLE
101107
YY
@@ -114,86 +120,10 @@ export default class App extends Component <{}, AppState> {
114120
<p>SCROLL</p>
115121
</div>
116122

117-
{false && (
118-
<RemoveScroll enabled={false && !!(this.state.counter % 2)}>
119-
<div
120-
style={{
121-
position: 'absolute',
122-
overflow: 'scroll',
123-
left: 0,
124-
right: 0,
125-
top: '100px',
126-
//width: '100%',
127-
height: '150px',
128-
backgroundColor: 'rgba(0,1,0,0.5)'
129-
}}
130-
// className={fullWidthClassName}
131-
>
132-
XXX
133-
XXX
134-
XXX
135-
{fill(20, 1).map(x => <p>{x}****</p>)}
136-
</div>
137-
</RemoveScroll>
138-
)}
139-
140-
{false && (
141-
<>
142-
<div
143-
style={{
144-
position: 'fixed',
145-
overflow: 'scroll',
146-
left: 0,
147-
right: 0,
148-
top: '150px',
149-
//width: '100%',
150-
height: '50px',
151-
backgroundColor: 'rgba(0,0,0,0.5)'
152-
}}
153-
className={RemoveScroll.classNames.fullWidth}
154-
>
155-
XXX
156-
XXX
157-
XXX
158-
{fill(20, 1).map(x => <p>{x}****</p>)}
159-
</div>
160-
161-
162-
<div style={{
163-
position: 'absolute',
164-
overflow: 'scroll',
165-
left: 0,
166-
right: 0,
167-
top: 200,
168-
//width: '100%',
169-
height: 300,
170-
backgroundColor: 'rgba(0,0,0,0.5)'
171-
}}>
172-
XXX
173-
XXX
174-
XXX
175-
176-
<div style={{
177-
position: 'absolute',
178-
overflow: 'scroll',
179-
width: 200,
180-
height: 200,
181-
backgroundColor: 'rgba(0,0,0,0.5)'
182-
}}>
183-
ZZZ
184-
ZZZ
185-
{fill(20, 1).map(x => <p>{x}****</p>)}
186-
</div>
187-
188-
{fill(20, 1).map(x => <p>{x}****</p>)}
189-
</div>
190-
</>
191-
)}
192-
193123
<p>FILLER (not scrollable)</p>
194-
{fill(100, 1).map((x, index) => <p>{index}**** </p>)}
124+
{fill(100, 1).map((_, index) => <p>{index}**** </p>)}
195125
<p>END</p>
196-
</AppWrapper>
126+
</div>
197127
)
198128
}
199129
}

0 commit comments

Comments
 (0)