about summary refs log tree commit diff
path: root/modules/bottom-sheet/src/BottomSheet.tsx
blob: 9e7d0c2091659312fb51ae89bbbb766cab274d9a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import * as React from 'react'
import {
  Dimensions,
  NativeSyntheticEvent,
  Platform,
  StyleProp,
  View,
  ViewStyle,
} from 'react-native'
import {requireNativeModule, requireNativeViewManager} from 'expo-modules-core'

import {BottomSheetState, BottomSheetViewProps} from './BottomSheet.types'

const screenHeight = Dimensions.get('screen').height

const NativeView: React.ComponentType<
  BottomSheetViewProps & {
    ref: React.RefObject<any>
    style: StyleProp<ViewStyle>
  }
> = requireNativeViewManager('BottomSheet')

const NativeModule = requireNativeModule('BottomSheet')

export class BottomSheet extends React.Component<
  BottomSheetViewProps,
  {
    open: boolean
  }
> {
  ref = React.createRef<any>()

  constructor(props: BottomSheetViewProps) {
    super(props)
    this.state = {
      open: false,
    }
  }

  present() {
    this.setState({open: true})
  }

  dismiss() {
    this.ref.current?.dismiss()
  }

  private onStateChange = (
    event: NativeSyntheticEvent<{state: BottomSheetState}>,
  ) => {
    const {state} = event.nativeEvent
    const isOpen = state !== 'closed'
    this.setState({open: isOpen})
    this.props.onStateChange?.(event)
  }

  private updateLayout = () => {
    this.ref.current?.updateLayout()
  }

  static dismissAll = async () => {
    await NativeModule.dismissAll()
  }

  render() {
    const {children, backgroundColor, ...rest} = this.props
    const cornerRadius = rest.cornerRadius ?? 0

    if (!this.state.open) {
      return null
    }

    return (
      <NativeView
        {...rest}
        onStateChange={this.onStateChange}
        ref={this.ref}
        style={{
          position: 'absolute',
          height: screenHeight,
          width: '100%',
        }}
        containerBackgroundColor={backgroundColor}>
        <View
          style={[
            {
              flex: 1,
              backgroundColor,
            },
            Platform.OS === 'android' && {
              borderTopLeftRadius: cornerRadius,
              borderTopRightRadius: cornerRadius,
            },
          ]}>
          <View onLayout={this.updateLayout}>{children}</View>
        </View>
      </NativeView>
    )
  }
}