Skip to content

Commit cb2569f

Browse files
refactor: replace Children.map by createcontext(#104)
1 parent 86cc1b6 commit cb2569f

File tree

6 files changed

+73
-64
lines changed

6 files changed

+73
-64
lines changed

README.md

+25-13
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
# React Scrollama 🦙
22

33
<p align="left">
4-
<a href="https://www.npmjs.com/package/react-scrollama">
5-
<img src="https://img.shields.io/npm/v/react-scrollama.svg" alt="npm version"/>
4+
<a href="https://npmjs.com/package/react-scrollama">
5+
<img src="https://img.shields.io/npm/v/react-scrollama?style=flat&colorA=080f12&colorB=1fa669" alt="npm version"/>
6+
</a>
7+
<a href="https://npmjs.com/package/react-scrollama">
8+
<img src="https://img.shields.io/npm/dm/react-scrollama?style=flat&colorA=080f12&colorB=1fa669" alt="npm downloads"/>
9+
</a>
10+
<a href="https://bundlephobia.com/result?p=react-scrollama">
11+
<img src="https://img.shields.io/bundlephobia/minzip/react-scrollama?style=flat&colorA=080f12&colorB=1fa669&label=minzip" alt="package size"/>
12+
</a>
13+
<a href="https://github.com/jsonkao/react-scrollama/blob/master/LICENSE">
14+
<img src="https://img.shields.io/github/license/jsonkao/react-scrollama.svg?style=flat&colorA=080f12&colorB=1fa669" alt="license"/>
15+
</a>
16+
<a href="https://www.jsdocs.io/package/react-scrollama">
17+
<img src="https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=1fa669" alt="jsdocs reference"/>
618
</a>
719
</p>
820

@@ -138,14 +150,14 @@ React Scrollama components do not render into the DOM. They are meant to set up
138150

139151
These are the props you can set on the `Scrollama` component itself:
140152

141-
| Prop | Type | Default | Description |
142-
|----------------|---------------------------|---------|-----------------------------------------------------------------------------------------|
143-
| offset | `number` (from 0 to 1) or pixel value (e.g. "300px") | 0.3 | How far from the top of the viewport to trigger a step (as a proportion of view height) |
144-
| threshold | `number` (greater than 1) | 4 | Granularity of the progress interval in pixels (smaller = more granular) |
145-
| onStepEnter | `function` | | Callback that fires when the top or bottom edge of a step enters the offset threshold. |
146-
| onStepExit | `function` | | Callback that fires when the top or bottom edge of a step exits the offset threshold. |
147-
| onStepProgress | `function` | | Callback that fires the progress a step has made through the threshold. |
148-
| debug | `boolean` | false | Whether to show visual debugging tools. |
153+
| Prop | Type | Default | Description |
154+
|----------------|------------------------------------------------------|---------|-----------------------------------------------------------------------------------------|
155+
| offset | `number` (from 0 to 1) or pixel value (e.g. "300px") | 0.3 | How far from the top of the viewport to trigger a step (as a proportion of view height) |
156+
| threshold | `number` (greater than 1) | 4 | Granularity of the progress interval in pixels (smaller = more granular) |
157+
| onStepEnter | `function` | | Callback that fires when the top or bottom edge of a step enters the offset threshold. |
158+
| onStepExit | `function` | | Callback that fires when the top or bottom edge of a step exits the offset threshold. |
159+
| onStepProgress | `function` | | Callback that fires the progress a step has made through the threshold. |
160+
| debug | `boolean` | false | Whether to show visual debugging tools. |
149161

150162
The `onStepEnter` and `onStepExit` callbacks receive one argument, an object, with the following properties:
151163

@@ -178,9 +190,9 @@ A `Step` element can contain one child, which must be a DOM element. To use a Re
178190

179191
These are the props you can set on the `Step` component:
180192

181-
| Prop | Type | Default | Description |
182-
|------|------|---------|------------------------------------------------------------------|
183-
| data | any | | Data to be given to `<Scrollama>` callbacks when step triggered. |
193+
| Prop | Type | Default | Description |
194+
|------|---------|---------|------------------------------------------------------------------|
195+
| data | unknown | | Data to be given to `<Scrollama>` callbacks when step triggered. |
184196

185197
You will also probably want to set a `key` prop on each `Step` if you're transforming an array of data into a list of `Step` elements (see [Lists and Keys](https://reactjs.org/docs/lists-and-keys.html)).
186198

src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './types';
33
export * from './utils';
44
export * from './step';
55
export * from './scrollama';
6+
export * from './provide';

src/provide.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createContext } from "react";
2+
3+
import type { ScrollamaProvideProps } from "./types";
4+
5+
/**
6+
* @see https://react.dev/reference/react/createContext#createcontext
7+
*/
8+
export const ScrollamaProvide = createContext<ScrollamaProvideProps<unknown>>({});

src/scrollama.tsx

+18-26
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import { useMemo, useState, Fragment, Children, useEffect, cloneElement, isValidElement } from 'react';
1+
import { useMemo, useState, useEffect } from 'react';
2+
23
import { DebugOffset } from './debug-offset';
34
import { isOffsetInPixels, createThreshold, isBrowser } from './utils';
5+
import { ScrollamaProvide } from './provide';
46

5-
import type { ScrollamaProps, StepProps } from './types';
7+
import type { ScrollamaProps } from './types';
68

79

8-
export const Scrollama = <T = string>({
10+
export const Scrollama = <T = unknown>({
911
debug,
1012
children,
1113
offset = 0.3,
@@ -39,33 +41,23 @@ export const Scrollama = <T = string>({
3941

4042
const offsetValue = isOffsetDefinedInPixels
4143
? (+(offset as string).replace('px', '') / innerHeight)
42-
: offset;
44+
: +offset;
4345

4446
const progressThreshold = useMemo(() => createThreshold(threshold, innerHeight), [innerHeight]);
4547

4648
return (
47-
<Fragment>
49+
<ScrollamaProvide.Provider value={{
50+
offset: offsetValue,
51+
lastScrollTop,
52+
handleSetLastScrollTop,
53+
progressThreshold,
54+
innerHeight,
55+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
56+
// @ts-expect-error
57+
onStepEnter, onStepExit, onStepProgress,
58+
}}>
4859
{debug && <DebugOffset offset={offset} />}
49-
{Children.map(children, (child, i) => {
50-
/**
51-
* Clone a React element.If the value is
52-
* not a valid React element, return child.
53-
*/
54-
if (!isValidElement(child)) {
55-
return child;
56-
}
57-
return cloneElement(child, {
58-
scrollamaId: `react-scrollama-${i}`,
59-
offset: offsetValue,
60-
onStepEnter,
61-
onStepExit,
62-
onStepProgress,
63-
lastScrollTop,
64-
handleSetLastScrollTop,
65-
progressThreshold,
66-
innerHeight
67-
} as unknown as StepProps);
68-
})}
69-
</Fragment>
60+
{children}
61+
</ScrollamaProvide.Provider>
7062
);
7163
};

src/step.tsx

+15-14
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
1-
import { useState, useEffect, useMemo, useCallback, useRef, Children, cloneElement } from 'react';
1+
import { useState, useEffect, useMemo, useCallback, useRef, Children, cloneElement, useContext } from 'react';
22
import { useInView } from 'react-intersection-observer';
33

44
import { isBrowser, getRootMargin, getProgressRootMargin } from './utils';
55
import type { StepProps } from './types';
6+
import { ScrollamaProvide } from './provide';
67

78
export const Step: React.FC<StepProps> = ({
89
children,
910
data,
10-
handleSetLastScrollTop = () => { },
11-
lastScrollTop = 0,
12-
onStepEnter = () => { },
13-
onStepExit = () => { },
14-
onStepProgress = null,
15-
offset = 0.3,
16-
scrollamaId = '',
17-
progressThreshold,
18-
innerHeight = 0,
1911
}) => {
12+
const {
13+
handleSetLastScrollTop = () => { },
14+
lastScrollTop = 0,
15+
onStepEnter = () => { },
16+
onStepExit = () => { },
17+
onStepProgress = null,
18+
offset = 0.3,
19+
progressThreshold,
20+
innerHeight = 0,
21+
} = useContext(ScrollamaProvide);
22+
2023
const rootMargin = getRootMargin({ offset });
2124
const { ref: inViewRef, entry } = useInView({
2225
rootMargin,
@@ -57,7 +60,6 @@ export const Step: React.FC<StepProps> = ({
5760
if (onStepProgress) {
5861
onStepProgress({
5962
progress,
60-
scrollamaId,
6163
data,
6264
element: scrollProgressEntry.target,
6365
entry: scrollProgressEntry,
@@ -70,18 +72,17 @@ export const Step: React.FC<StepProps> = ({
7072
useEffect(() => {
7173
if (entry && !entry.isIntersecting && isIntersecting) {
7274
setIsIntersecting(false);
73-
onStepExit({ element: entry.target, scrollamaId, data, entry, direction });
75+
onStepExit({ element: entry.target, data, entry, direction });
7476
handleSetLastScrollTop(scrollTop)
7577
} else if (entry && entry.isIntersecting && !isIntersecting) {
7678
setIsIntersecting(true);
77-
onStepEnter({ element: entry.target, scrollamaId, data, entry, direction });
79+
onStepEnter({ element: entry.target, data, entry, direction });
7880
handleSetLastScrollTop(scrollTop)
7981
}
8082
}, [entry]);
8183

8284
const childElement = Children.only(children);
8385
return cloneElement(childElement, {
84-
'data-react-scrollama-id': scrollamaId,
8586
ref: setRefs,
8687
entry,
8788
});

src/types.ts

+6-11
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ export interface ScrollamaCallbackData<T = unknown> {
1616
direction: ScrollamaDirection;
1717
/** The IntersectionObserverEntry for the step */
1818
entry: IntersectionObserverEntry;
19-
/** Unique identifier for the Scrollama instance */
20-
scrollamaId: string;
2119
}
2220

2321
/**
@@ -102,7 +100,9 @@ export interface StepProps<T = unknown> {
102100
* Optional data associated with this step.
103101
*/
104102
data?: T;
103+
}
105104

105+
export interface ScrollamaProvideProps<T = unknown> {
106106
/**
107107
* The last known scroll position.
108108
*/
@@ -113,15 +113,10 @@ export interface StepProps<T = unknown> {
113113
*/
114114
offset?: number;
115115

116-
/**
117-
* A unique identifier for this Scrollama instance.
118-
*/
119-
scrollamaId?: string;
120-
121116
/**
122117
* The threshold for progress calculations.
123118
*/
124-
progressThreshold?: number;
119+
progressThreshold?: number | number[];
125120

126121
/**
127122
* The inner height of the viewport.
@@ -131,17 +126,17 @@ export interface StepProps<T = unknown> {
131126
/**
132127
* Callback fired when the step enters the viewport.
133128
*/
134-
onStepEnter?: ScrollamaCallback;
129+
onStepEnter?: ScrollamaCallback<T>;
135130

136131
/**
137132
* Callback fired when the step exits the viewport.
138133
*/
139-
onStepExit?: ScrollamaCallback;
134+
onStepExit?: ScrollamaCallback<T>;
140135

141136
/**
142137
* Callback fired to report progress as the step moves through the viewport.
143138
*/
144-
onStepProgress?: ScrollamaProgressCallback;
139+
onStepProgress?: ScrollamaProgressCallback<T>;
145140

146141
/**
147142
* Function to update the last known scroll position.

0 commit comments

Comments
 (0)