Skip to content

Commit 4e7de29

Browse files
committed
fix: add proper typings for PlainChildren rendering
1 parent 1321c5c commit 4e7de29

File tree

4 files changed

+39
-17
lines changed

4 files changed

+39
-17
lines changed

src/InView.tsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import * as React from 'react'
22
import invariant from 'invariant'
33
import { observe, unobserve } from './intersection'
4-
import { IntersectionObserverProps } from './typings/types'
4+
import { IntersectionObserverProps, PlainChildrenProps } from './typings/types'
55

66
type State = {
77
inView: boolean
88
entry?: IntersectionObserverEntry
99
}
1010

11+
function isPlainChildren(
12+
props: IntersectionObserverProps | PlainChildrenProps,
13+
): props is PlainChildrenProps {
14+
return typeof props.children !== 'function'
15+
}
16+
1117
/**
1218
* Monitors scroll, and triggers the children function with updated props
1319
*
@@ -17,7 +23,10 @@ type State = {
1723
)}
1824
</InView>
1925
*/
20-
export class InView extends React.Component<IntersectionObserverProps, State> {
26+
export class InView extends React.Component<
27+
IntersectionObserverProps | PlainChildrenProps,
28+
State
29+
> {
2130
static displayName = 'InView'
2231
static defaultProps = {
2332
threshold: 0,
@@ -65,7 +74,7 @@ export class InView extends React.Component<IntersectionObserverProps, State> {
6574
}
6675
}
6776

68-
node: HTMLElement | null = null
77+
node: Element | null = null
6978

7079
observeNode() {
7180
if (!this.node) return
@@ -77,7 +86,7 @@ export class InView extends React.Component<IntersectionObserverProps, State> {
7786
})
7887
}
7988

80-
handleNode = (node?: HTMLElement) => {
89+
handleNode = (node?: Element | null) => {
8190
if (this.node) unobserve(this.node)
8291
this.node = node ? node : null
8392
this.observeNode()
@@ -91,6 +100,11 @@ export class InView extends React.Component<IntersectionObserverProps, State> {
91100
}
92101

93102
render() {
103+
const { inView, entry } = this.state
104+
if (!isPlainChildren(this.props)) {
105+
return this.props.children({ inView, entry, ref: this.handleNode })
106+
}
107+
94108
const {
95109
children,
96110
as,
@@ -102,13 +116,6 @@ export class InView extends React.Component<IntersectionObserverProps, State> {
102116
...props
103117
} = this.props
104118

105-
const { inView, entry } = this.state
106-
107-
if (typeof children === 'function') {
108-
// @ts-ignore doesn't properly detect the function here...
109-
return children({ inView, entry, ref: this.handleNode })
110-
}
111-
112119
return React.createElement(
113120
as || tag || 'div',
114121
{ ref: this.handleNode, ...props },

src/typings/types.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,33 @@ export type IntersectionObserverProps = IntersectionOptions & {
1717
* contain an `inView` boolean and `ref` that should be
1818
* assigned to the element root.
1919
*/
20-
children?: React.ReactNode | ((fields: RenderProps) => React.ReactNode)
20+
children: (fields: RenderProps) => React.ReactNode
21+
22+
/** Call this function whenever the in view state changes */
23+
onChange?: (inView: boolean, entry: IntersectionObserverEntry) => void
24+
}
25+
26+
/**
27+
* Types specific to the PlainChildren rendering of InView
28+
* */
29+
export type PlainChildrenProps = IntersectionOptions & {
30+
children: React.ReactNode
2131

2232
/**
2333
* Render the wrapping element as this element.
2434
* @default `'div'`
2535
*/
26-
as?: string
36+
as?: React.ReactType<any>
2737

2838
/**
2939
* Element tag to use for the wrapping component
3040
* @deprecated Replace with the 'as' prop
3141
*/
32-
tag?: string
42+
tag?: React.ReactType<any>
3343

3444
/** Call this function whenever the in view state changes */
3545
onChange?: (inView: boolean, entry: IntersectionObserverEntry) => void
36-
}
46+
} & React.HTMLProps<HTMLDivElement>
3747

3848
export type HookResponse = [
3949
((node?: Element | null) => void),

stories/Hooks.story.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import * as React from 'react'
22
import { storiesOf } from '@storybook/react'
33
import { action } from '@storybook/addon-actions'
4-
import { useInView, IntersectionOptions } from '../src/index'
4+
import { useInView } from '../src/index'
55
import ScrollWrapper from './ScrollWrapper/index'
66
import { CSSProperties } from 'react'
7+
import { IntersectionOptions } from '../src/typings/types'
78

89
type Props = {
910
style?: Object

stories/InView.story.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ storiesOf('Intersection Observer', module)
5050
))
5151
.add('Plain children', () => (
5252
<ScrollWrapper>
53-
<InView onChange={action('Child Observer inview')}>
53+
<InView
54+
onChange={action('Child Observer inview')}
55+
className="custom-class"
56+
as="div"
57+
>
5458
<Header>Plain children</Header>
5559
</InView>
5660
</ScrollWrapper>

0 commit comments

Comments
 (0)