Skip to content

Commit ad55c64

Browse files
authored
feat: add isDisabled prop ParallaxProvider to disable the controller #183 (#207)
1 parent 35af877 commit ad55c64

File tree

8 files changed

+119
-14
lines changed

8 files changed

+119
-14
lines changed

documentation/docs/usage/components/parallax-provider.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ The following props configure the `<ParallaxProvider>` component:
3838
| ------------------- | :-----------: | :--------- | ------------------------------------------------------------------------------------------------------------------------ |
3939
| **scrollAxis** | `string` | `vertical` | Optionally pass the scroll axis for setting horizontal/vertical scrolling. One of `vertical` or `horizontal` |
4040
| **scrollContainer** | `HTMLElement` | `<body>` | Optionally set the container that has overflow and will contain parallax elements. Defaults to the document scroll body. |
41+
| **isDisabled** | `boolean` | `false` | Disables the ParallaxController and all animations. |
4142

4243
## More Examples
4344

@@ -83,3 +84,21 @@ const ScrollContainer = () => {
8384
);
8485
};
8586
```
87+
88+
### Disabling All Parallax Elements
89+
90+
With the `isDisabled` prop you may disable every parallax element in the provider when a condition is met, instead of individually. This can be helpful to disable parallax in certain situations like on mobile devices, or for users who [prefers-reduced-motion](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion). Elements will be re-enabled when `isDisabled` is `true`.
91+
92+
```tsx
93+
const App = () => {
94+
const userPrefersReducedMotion = useMediaQuery({
95+
query: '(prefers-reduced-motion)',
96+
});
97+
98+
return (
99+
<ParallaxProvider isDisabled={userPrefersReducedMotion}>
100+
{props.children}
101+
</ParallaxProvider>
102+
);
103+
};
104+
```

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
}
9393
],
9494
"dependencies": {
95-
"parallax-controller": "^1.5.0"
95+
"parallax-controller": "^1.7.0"
9696
},
9797
"devDependencies": {
9898
"@babel/core": "^7.17.8",

src/components/ParallaxProvider/index.test.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ describe('A <ParallaxProvider>', () => {
4848
expect(parallaxController).toBeInstanceOf(ParallaxController);
4949
});
5050

51+
it('to disable parallax elements and re-enable', () => {
52+
let parallaxController: ParallaxController | null = null;
53+
54+
const ContextChecker = () => {
55+
parallaxController = useParallaxController();
56+
if (parallaxController) {
57+
parallaxController.disableParallaxController = jest.fn();
58+
parallaxController.enableParallaxController = jest.fn();
59+
}
60+
return null;
61+
};
62+
63+
const context = render(
64+
<ParallaxProvider isDisabled>
65+
<ContextChecker />
66+
</ParallaxProvider>
67+
);
68+
69+
expect(
70+
// @ts-expect-error
71+
parallaxController.disableParallaxController
72+
).toBeCalled();
73+
74+
context.rerender(
75+
<ParallaxProvider>
76+
<ContextChecker />
77+
</ParallaxProvider>
78+
);
79+
80+
expect(
81+
// @ts-expect-error
82+
parallaxController.enableParallaxController
83+
).toBeCalled();
84+
});
85+
5186
it('to destroy the controller when unmounting', () => {
5287
const node = document.createElement('div');
5388

src/components/ParallaxProvider/index.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,27 @@ export class ParallaxProvider extends Component<ParallaxProviderProps, {}> {
2020
});
2121
}
2222

23+
componentDidMount() {
24+
if (this.props.isDisabled) {
25+
this.controller?.disableParallaxController();
26+
}
27+
}
28+
2329
componentDidUpdate(prevProps: ParallaxProviderProps) {
24-
if (prevProps.scrollContainer !== this.props.scrollContainer) {
25-
// @ts-ignore
26-
this.controller.updateScrollContainer(this.props.scrollContainer);
30+
if (
31+
prevProps.scrollContainer !== this.props.scrollContainer &&
32+
this.props.scrollContainer
33+
) {
34+
this.controller?.updateScrollContainer(this.props.scrollContainer);
35+
}
36+
37+
if (prevProps.isDisabled !== this.props.isDisabled) {
38+
if (this.props.isDisabled) {
39+
this.controller?.disableParallaxController();
40+
}
41+
if (!this.props.isDisabled) {
42+
this.controller?.enableParallaxController();
43+
}
2744
}
2845
}
2946

src/components/ParallaxProvider/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,8 @@ export interface ParallaxProviderProps {
1111
* to the HTML body
1212
*/
1313
scrollContainer?: HTMLElement;
14+
/**
15+
* Disables the ParallaxController and all animations.
16+
*/
17+
isDisabled?: boolean;
1418
}

stories/Container.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
import { ScrollAxis } from 'parallax-controller';
21
import React from 'react';
32
import { PropsWithChildren } from 'react';
43
import { ParallaxProvider } from '../src';
4+
import { ParallaxProviderProps } from '../src/components/ParallaxProvider/types';
55

66
type ContainerProps = PropsWithChildren<{
7-
scrollAxis: ScrollAxis;
87
className?: string;
9-
}>;
8+
}> &
9+
ParallaxProviderProps;
1010

11-
export const Container = (props: ContainerProps) => (
12-
<ParallaxProvider scrollAxis={props.scrollAxis}>
11+
export const Container = ({
12+
className,
13+
children,
14+
...props
15+
}: ContainerProps) => (
16+
<ParallaxProvider {...props}>
1317
<div className={props.scrollAxis}>
14-
<div className={props.className}>{props.children}</div>
18+
<div className={className}>{children}</div>
1519
</div>
1620
</ParallaxProvider>
1721
);

stories/Parallax/1_ParallaxVertical.stories.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,32 @@ export const WithAHundredElements = () => {
215215
);
216216
};
217217

218+
export const WithParallaxElementsGloballyDisabled = (args) => {
219+
const amount = 100;
220+
const elements = new Array(amount).fill(null).map((x, i) => i);
221+
222+
return (
223+
<Container scrollAxis="vertical" isDisabled={args.isDisabled}>
224+
<div className={styles.elements}>
225+
{elements.map((_, i) => {
226+
const props: ParallaxProps = propConfigs[i % propConfigs.length];
227+
return (
228+
<div key={i} className={styles.small} style={{ perspective: 800 }}>
229+
<Parallax {...props}>
230+
<Element name={i + 1} />
231+
</Parallax>
232+
</div>
233+
);
234+
})}
235+
</div>
236+
</Container>
237+
);
238+
};
239+
240+
WithParallaxElementsGloballyDisabled.args = {
241+
isDisabled: true,
242+
};
243+
218244
export const InsideADiv = () => {
219245
const amount = 2;
220246
const offA = -50;

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11140,10 +11140,10 @@ pako@~1.0.5:
1114011140
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
1114111141
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
1114211142

11143-
parallax-controller@^1.5.0:
11144-
version "1.5.0"
11145-
resolved "https://registry.yarnpkg.com/parallax-controller/-/parallax-controller-1.5.0.tgz#324859f336566f114b8c08212b8454b6ad17de0f"
11146-
integrity sha512-X7FKD0bH27hJHdknH/UNEznmw6xjcWz/QA4M6RLlE/gUXfbePKhk+ld/20e58aAfjMqj+Q7RURryISFcDIVmtA==
11143+
parallax-controller@^1.7.0:
11144+
version "1.7.0"
11145+
resolved "https://registry.yarnpkg.com/parallax-controller/-/parallax-controller-1.7.0.tgz#659e8176922034ac548009ac544951432330aa0a"
11146+
integrity sha512-tIU/LgH9oIrvC6o+rvGQis8/NXxsHNuF5LODmcc5TjvEDUi2qiR/iisFmyaqI9LImQ3psdAv28k2ZEAnFekiig==
1114711147
dependencies:
1114811148
bezier-easing "^2.1.0"
1114911149

0 commit comments

Comments
 (0)