-
Notifications
You must be signed in to change notification settings - Fork 5
Open
Description
So I actually also setup Slack's library with my react native app for the bottom sheet a few weeks ago!
Here's the relevant code in case its helpful. I haven't had time to move it into an open source library yet.
- Mine has a sticky header at the top which is rendered above the pan sheet.
- Inside the pan sheet, it supports multiple scrollviews via react context (code snippet at the bottom).
- I expose methods to programmatically transition between short and longform height
- a react context that lets any child in the pan sheet view can easily change the state. It does this ~synchronously via the JSI.
This is how I use it in JS:
<View style={{ flex: 1 }}>
<PanSheetView
ref={this.panSheet}
screenOffset={showStart ? TOP_HEADER : LIST_HEADER_HEIGHT + 8}
headerTag={this.headerTag}
screenMinY={TOP_Y}
longHeight={SCREEN_DIMENSIONS.height - TOP_Y}
defaultPresentationState={
this.props.initialStep === GalleryStep.searchInput
? PanSheetViewSize.tall
: PanSheetViewSize.short
}
shortHeight={
SCREEN_DIMENSIONS.height -
TOP_Y -
(showStart ? TOP_HEADER : LIST_HEADER_HEIGHT)
}
onDismiss={this.handleDismiss}
onWillDismiss={this.handleWillDismiss}
didAppear={this.showHeader}
>
<View style={styles.container}>{this.renderStep()}</View>
</PanSheetView>
{showStart && (
<StartFromHeader ref={this.startFromHeader} scrollY={this.scrollY} />
)}
</View>This is all the relevant code I think:
//
// PanViewManager.swift
// yeet
//
// Created by Jarred WSumner on 2/11/20.
// Copyright © 2020 Yeet. All rights reserved.
//
import Foundation
protocol PanHostViewInteractor {
func present(_ modalHostView: PanViewSheet!, with viewController: UIViewController!, animated: Bool)
func dismiss(_ modalHostView: PanViewSheet!, with viewController: UIViewController!, animated: Bool)
}
@objc(PanViewManager)
class PanViewManager : RCTViewManager, PanHostViewInteractor, RCTInvalidating {
func present(_ modalHostView: PanViewSheet!, with viewController: UIViewController!, animated: Bool) {
let panView: PanViewSheet = modalHostView as! PanViewSheet
guard let _viewController = panView.reactSuperview()?.reactViewController() else {
return
}
guard !panView.presented else {
return
}
guard panView.reactSubview != nil else {
return
}
guard !(panView.panViewController?.isPanModalPresented ?? false) else {
return
}
panView.panViewController?.panPresentationState = panView._defaultPresentationState
panView.presented = true
// Wait a tick.
_viewController.presentPanModal(panView.panViewController!)
panView.onPresent(_viewController)
}
@objc(invalidate) func invalidate() {
hostViews.allObjects.forEach { view in
view.invalidate()
}
hostViews.removeAllObjects()
}
func dismiss(_ modalHostView: PanViewSheet!, with viewController: UIViewController!, animated: Bool) {
var panView: PanViewSheet = modalHostView as! PanViewSheet
panView.panViewController?.dismiss(animated: animated)
}
override func view() -> UIView! {
Log.debug("BEFORE")
var _view = PanViewSheet(bridge: bridge)
Log.debug("HERE")
let panViewController = PanViewController(bridge: bridge)
_view.panViewController = panViewController
_view.delegate = self;
hostViews.add(_view)
return _view
}
override static func moduleName() -> String! {
return "PanSheetView";
}
@objc(clearPanView:)
func clearPanView(_ tag: NSNumber) {
RCTExecuteOnMainQueue {
guard let panView = self.bridge?.uiManager?.view(forReactTag: tag) as? PanViewSheet else {
return
}
if panView.panViewController?.isPanModalPresented ?? false {
panView.panViewController?.dismiss(animated: true)
}
panView.bridge = nil
}
}
var hostViews = NSHashTable<PanViewSheet>(options: .weakMemory)
override func shadowView() -> RCTShadowView! {
return PanShadowView()
}
@objc(presentViewManagerFrom:to:) func presentViewManager(_ from: NSNumber, _ to: NSNumber) {
guard var bridge = self.bridge else {
return
}
RCTExecuteOnMainQueue {
guard let panView = bridge.uiManager.view(forReactTag: to) as? PanViewSheet else {
return
}
panView.presentIt()
}
}
@objc(transition:to:) func transition(_ tag: NSNumber, _ to: String) {
guard var bridge = self.bridge else {
return
}
guard bridge.isValid && !bridge.isLoading else {
return
}
let presentationState = PanViewSheet.PAN_PRESENTATION_STATE_CONVERTER[to] ?? .longForm
RCTExecuteOnMainQueue { [weak bridge] in
guard let panView = bridge?.uiManager?.view(forReactTag: tag) as? PanViewSheet else {
return
}
guard let panViewController = panView.panViewController else {
return
}
if to == "dismiss" {
panViewController.dismiss(animated: true, completion: nil)
} else {
panViewController.transition(to: presentationState)
}
}
}
override static func requiresMainQueueSetup() -> Bool {
return true
}
}//
// PanShadowView.m
// yeet
//
// Created by Jarred WSumner on 2/11/20.
// Copyright © 2020 Yeet. All rights reserved.
//
#import "PanShadowView.h"
#import <React/RCTUtils.h>
@implementation PanShadowView
- (void)insertReactSubview:(id<RCTComponent>)subview atIndex:(NSInteger)atIndex
{
[super insertReactSubview:subview atIndex:atIndex];
if ([subview isKindOfClass:[RCTShadowView class]]) {
((RCTShadowView *)subview).size = RCTScreenSize();
}
}
@end//
// ReactNativePanViewController.swift
// yeet
//
// Created by Jarred WSumner on 2/11/20.
// Copyright © 2020 Yeet. All rights reserved.
//
import Foundation
import PanModal
@objc(PanViewController)
class PanViewController : UIViewController, PanModalPresentable {
weak var bridge: RCTBridge? = nil
var panViewTag: NSNumber? = nil
var panView: PanViewSheet? {
guard panViewTag != nil else {
return nil
}
return bridge?.uiManager?.view(forReactTag: panViewTag) as? PanViewSheet
}
init(bridge: RCTBridge?) {
self.bridge = bridge
super.init(nibName: nil, bundle: nil)
self.view = UIView(frame: UIScreen.main.bounds)
self.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.modalPresentationStyle = .custom
}
override func loadView() {
super.loadView()
self.view.clipsToBounds = false
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { get { return .portrait } }
func supportedInterfaceOrientations(for window: UIWindow?) -> UIInterfaceOrientationMask {
return .portrait
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
get {
return .portrait
}
set {
}
}
@objc(longHeight) var longHeight : CGFloat = UIScreen.main.bounds.height {
didSet {
self.panModalSetNeedsLayoutUpdate()
}
}
@objc(shortHeight) var shortHeight : CGFloat = UIScreen.main.bounds.height - 100 {
didSet {
self.panModalSetNeedsLayoutUpdate()
}
}
var panScrollView : UIScrollView? {
get {
let view = bridge?.uiManager.view(forReactTag: panScrollTag)
if let _view = view as? RCTScrollView {
return _view.scrollView
} else if type(of: view) == UIScrollView.self {
return view as! UIScrollView
} else {
return nil
}
}
}
var panScrollTag: NSNumber? = nil
var panScrollable: UIScrollView? {
get {
if let scrollView = self.panScrollView {
return scrollView
} else {
return nil
}
}
}
var hasLoaded = false
override func viewDidLoad() {
super.viewDidLoad()
hasLoaded = true
// panModalSetNeedsLayoutUpdate()
// panModalTransition(to: panPresentationState)
}
var _topOffset = CGFloat(0)
var topOffset: CGFloat {
get {
return _topOffset
}
set (newValue) {
_topOffset = newValue
panModalSetNeedsLayoutUpdate()
}
}
// var panScrollable: UIScrollView? {
// return nil
// }
var longFormHeight: PanModalHeight {
return .contentHeightIgnoringSafeArea(longHeight)
}
var shortFormHeight: PanModalHeight {
return .contentHeightIgnoringSafeArea(shortHeight)
}
var transitionAnimationOptions: UIView.AnimationOptions {
return [.allowUserInteraction, .beginFromCurrentState]
}
var anchorModalToLongForm: Bool {
get { return panView?._defaultPresentationState == .longForm }
}
var shouldRoundTopCorners: Bool {
return false
}
func reloadHeader() {
RCTExecuteOnMainQueue {
guard let headerView = self.headerView else {
return
}
guard let reactSubview = self.panView?.reactSubview ?? nil else {
return
}
self.view.insertSubview(headerView, belowSubview: reactSubview)
}
}
var minY: CGFloat = 0
var allowsExtendedPanScrolling: Bool { true }
/**
A flag to determine if dismissal should be initiated when swiping down on the presented view.
Return false to fallback to the short form state instead of dismissing.
Default value is true.
*/
var allowsDragToDismiss: Bool { true }
/**
A flag to determine if dismissal should be initiated when tapping on the dimmed background view.
Default value is true.
*/
var allowsTapToDismiss: Bool { true }
/**
Notifies the delegate when the pan modal gesture recognizer state is either
`began` or `changed`. This method gives the delegate a chance to prepare
for the gesture recognizer state change.
For example, when the pan modal view is about to scroll.
Default value is an empty implementation.
*/
func willRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) {
guard let reactSubview = panView?.reactSubview else {
return
}
guard let headerView = self.headerView else {
return
}
guard let superview = view.superview else {
return
}
guard let window = UIApplication.shared.keyWindow else {
return
}
let dist = panModalGestureRecognizer.translation(in: window)
let totalDistance = dist.y + (headerView.frame.size.height - superview.frame.y)
let endY = totalDistance > 0 ? totalDistance : 0
if let dragIndicatorView = self.dragIndicatorView {
let endValue: Float = endY == 0 ? 1 : 0
if endValue != dragIndicatorView.layer.opacity {
panModalAnimate({
dragIndicatorView.layer.opacity = endValue
})
}
}
headerView.transform = CGAffineTransform.identity.translatedBy(x: .zero, y: endY)
}
/**
Asks the delegate if the pan modal gesture recognizer should be prioritized.
For example, you can use this to define a region
where you would like to restrict where the pan gesture can start.
If false, then we rely solely on the internal conditions of when a pan gesture
should succeed or fail, such as, if we're actively scrolling on the scrollView.
Default return value is false.
*/
func shouldPrioritize(panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool {
return false
}
/**
Asks the delegate if the pan modal should transition to a new state.
Default value is true.
*/
func shouldTransition(to state: PanModalPresentationController.PresentationState) -> Bool {
return true
}
var panPresentationState = PanModalPresentationController.PresentationState.shortForm
/**
Notifies the delegate that the pan modal is about to transition to a new state.
Default value is an empty implementation.
*/
func adjustHeaderPosition(state: PanModalPresentationController.PresentationState) {
if let headerView = self.headerView {
if state == .longForm {
panModalAnimate({
headerView.transform = CGAffineTransform.init(translationX: 0, y: (self.longHeight - self.shortHeight) )
})
} else {
panModalAnimate({
headerView.transform = .identity
})
}
}
}
func willTransition(to state: PanModalPresentationController.PresentationState) {
adjustHeaderPosition(state: state)
panView?.willTransition(to: state)
panPresentationState = state
panModalSetNeedsLayoutUpdate()
if let dragIndicatorView = self.dragIndicatorView {
let _alpha: Float = state == .longForm ? 0.0 : 1.0
if _alpha != dragIndicatorView.layer.opacity {
panModalAnimate({
dragIndicatorView.layer.opacity = _alpha
})
}
}
}
var dragIndicatorView: UIView? {
guard let panPresentationController = self.panPresentationController else {
return nil
}
return view.superview?.subviews.first(where: { view -> Bool in
return view.backgroundColor == self.dragIndicatorBackgroundColor
})
}
var panPresentationController: PanModalPresentationController? { return presentationController as? PanModalPresentationController }
var showDragIndicator: Bool {
return headerTag == nil
}
var headerTag: NSNumber? = nil {
didSet {
reloadHeader()
}
}
var headerView: UIView? {
guard let headerTag = self.headerTag else {
return nil
}
guard bridge?.isValid ?? false else {
return nil
}
guard let uiManager = bridge?.uiManager else {
return nil
}
return uiManager.view(forReactTag: headerTag)
}
/**
Notifies the delegate that the pan modal is about to be dismissed.
Default value is an empty implementation.
*/
func panModalWillDismiss() {
panView?.resetTouch()
panView?.onWillDismiss?([:])
if let headerView = self.headerView {
panModalAnimate({
self.headerView?.layer.opacity = 0
})
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
reloadHeader()
if let headerView = self.headerView {
headerView.layer.opacity = 0
panModalAnimate({
self.headerView?.layer.opacity = 1
})
}
// Force it to start in the long form
if panView?._defaultPresentationState == .longForm {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
self.transition(to: .longForm)
}
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
panView?.didAppear?([:])
reloadHeader()
headerView?.layer.opacity = 1
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let headerView = self.headerView {
panModalAnimate({
self.headerView?.layer.opacity = 0
})
}
}
func transition(to: PanModalPresentationController.PresentationState) {
panModalTransition(to: to)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
panView?.presented = false
panView?.resetTouch()
}
/**
Notifies the delegate after the pan modal is dismissed.
Default value is an empty implementation.
*/
func panModalDidDismiss() {
panView?.onDismiss?([:])
}
} //
// PanViewSheet.swift
// yeet
//
// Created by Jarred WSumner on 2/11/20.
// Copyright © 2020 Yeet. All rights reserved.
//
import Foundation
import UIKit
import PanModal
import SwiftyJSON
@objc(PanViewSheet)
class PanViewSheet : UIView {
override func didSetProps(_ changedProps: [String]!) {
if self.reactTag != nil {
self.panViewController?.panViewTag = reactTag
}
self._defaultPresentationState = PanViewSheet.PAN_PRESENTATION_STATE_CONVERTER[defaultPresentationState as String? ?? "shortForm"] ?? .shortForm
RCTExecuteOnMainQueue {
self.panViewController?.panModalSetNeedsLayoutUpdate()
}
}
override func didMoveToWindow() {
super.didMoveToWindow()
if superview == nil && window == nil {
return
}
guard superview != nil else {
return
}
guard !presented else {
return
}
if isDetached {
return
}
guard panViewController != nil else {
return
}
if (!self.isUserInteractionEnabled && !(superview?.reactSubviews()?.contains(self) ?? false)) {
return;
}
self.panViewController?.panViewTag = reactTag
self.panViewController?.topOffset = self.screenOffset
self.panViewController?.minY = self.screenMinY
self.panViewController?.longHeight = self.longHeight
self.panViewController?.shortHeight = self.shortHeight
if let reactSubview = self.reactSubview {
self.panViewController?.view.insertSubview(reactSubview, at: 0)
self.panViewController?.reloadHeader()
panViewController?.panModalSetNeedsLayoutUpdate()
}
delegate?.present(self, with: reactViewController(), animated: true)
presented = true
}
func presentIt() {
}
var canPresent = false
var delegate: PanHostViewInteractor? = nil
var invalidated = false
@objc(invalidate) func invalidate() {
guard !invalidated else {
return
}
self.invalidated = true
if presented {
dismissController()
}
resetTouch()
}
func resetTouch() {
guard let touchHandler = self.touchHandler else {
return
}
if RCTIsMainQueue() {
if let reactSubview = self.reactSubview {
if touchHandler.view == reactSubview {
touchHandler.detach(from: reactSubview)
}
}
}
touchHandler.cancel()
touchHandler.reset()
touchHandler.isEnabled = false
self.touchHandler = nil
}
var presented = false
override func didMoveToSuperview() {
super.didMoveToSuperview()
if (presented && superview == nil) {
self.dismissController()
}
}
func dismissController() {
presented = false
RCTExecuteOnMainQueue {
self.delegate?.dismiss(self, with: self.reactViewController(), animated: true)
}
}
@objc(containerTag) var containerTag: NSNumber? = nil
var touchHandler: RCTTouchHandler?
init(bridge: RCTBridge) {
self.bridge = bridge
touchHandler = RCTTouchHandler(bridge: bridge)
super.init(frame: .zero)
self.backgroundColor = .clear
}
var reactSubview : UIView? = nil
override func insertReactSubview(_ subview: UIView!, at atIndex: Int) {
super.insertReactSubview(subview, at: atIndex)
touchHandler?.attach(to: subview)
reactSubview = subview
}
@objc(headerTag) var headerTag: NSNumber? = nil {
didSet {
self.panViewController?.headerTag = self.headerTag
}
}
override func removeReactSubview(_ subview: UIView!) {
super.removeReactSubview(subview)
touchHandler?.detach(from: subview)
reactSubview = nil
}
@objc(longHeight) var longHeight : CGFloat = UIScreen.main.bounds.height {
didSet (newValue) {
self.panViewController?.longHeight = newValue
}
}
@objc(shortHeight) var shortHeight : CGFloat = UIScreen.main.bounds.height - 200 {
didSet (newValue) {
self.panViewController?.shortHeight = newValue
}
}
func onPresent(_ parent: UIViewController) {
// panViewController?.didMove(toParent: parent)
}
override func didUpdateReactSubviews() {
}
@objc(onWillDismiss)
var onWillDismiss: RCTDirectEventBlock? = nil
@objc(onDismiss)
var onDismiss: RCTDirectEventBlock? = nil
@objc(screenMinY)
var screenMinY : CGFloat = .zero {
didSet (newValue) {
self.panViewController?.minY = newValue
}
}
@objc(screenOffset)
var screenOffset : CGFloat = .zero {
didSet (newValue) {
self.panViewController?.topOffset = newValue
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc(panScrollTag) var panScrollTag: NSNumber? {
get {
return panViewController?.panScrollTag
}
set (newValue) {
Log.debug("PAN SCROL TAG \(newValue)")
panViewController?.panScrollTag = newValue
}
}
static let PAN_PRESENTATION_STATE_CONVERTER = [
"longForm": PanModalPresentationController.PresentationState.longForm,
"shortForm": PanModalPresentationController.PresentationState.shortForm
]
static let PAN_PRESENTATION_TO_STRING = Dictionary(grouping: PAN_PRESENTATION_STATE_CONVERTER.keys.sorted(), by: { PAN_PRESENTATION_STATE_CONVERTER[$0]! })
@objc(defaultPresentationState)
var defaultPresentationState : NSString? = nil
var _defaultPresentationState: PanModalPresentationController.PresentationState = .shortForm
@objc(onTransition)
var onTransition: RCTDirectEventBlock? = nil
func willTransition(to: PanModalPresentationController.PresentationState) {
guard let _onTransition = self.onTransition else {
return
}
let from: PanModalPresentationController.PresentationState = to == .longForm ? .shortForm : .longForm
_onTransition([
"from": PanViewSheet.PAN_PRESENTATION_TO_STRING[from]?.first,
"to": PanViewSheet.PAN_PRESENTATION_TO_STRING[to]?.first
])
}
@objc(didAppear)
var didAppear: RCTDirectEventBlock? = nil
@objc(bridge)
var bridge: RCTBridge? = nil
@objc(panViewController)
var panViewController: PanViewController? = nil {
didSet {
// self.panViewController?.boundsDidChangeBlock = { rect in
// guard let bridge = self.bridge else {
// return
// }
//
// guard !bridge.isLoading && bridge.isValid else {
// return
// }
//
// self.bridge?.uiManager.setSize(rect.size, for: self)
// }
}
}
override func layoutSubviews() {
super.layoutSubviews()
}
deinit {
resetTouch()
Log.debug("DEINIT PAN VIEW SHEET")
}
}import * as React from "react";
import {
requireNativeComponent,
NativeSyntheticEvent,
findNodeHandle,
View,
StyleSheet,
ScrollView as ScrollViewType,
LayoutAnimation
} from "react-native";
import FastList from "../FastList";
import {
presentPanSheetView,
PanSheetViewSize,
transitionPanSheetView
} from "../../lib/Yeet";
const ScrollView = require("react-native/Libraries/Components/ScrollView/ScrollView");
// const AppContainer = require("react-native/AppContainer");
type Props = {
screenOffset: number;
screenMinY: number;
panScrollTag: number | null;
longHeight: number;
shortHeight: number;
onDismiss: (event: NativeSyntheticEvent<any>) => void;
onWillDismiss: (event: NativeSyntheticEvent<any>) => void;
};
const NativePanSheetView = requireNativeComponent(
"PanView"
) as React.ComponentType<Props>;
type PanSheetContextValue = {
setActiveScrollView: (ref) => void;
setSize: (size: PanSheetViewSize) => void;
size: PanSheetViewSize;
panScrollTag: number | null;
};
export const PanSheetContext = React.createContext<PanSheetContextValue>({
setActiveScrollView: ref => null,
setSize: (size: PanSheetViewSize) => null,
panScrollTag: 0,
size: PanSheetViewSize.short
});
export class PanSheetView extends React.Component<
Props,
{ panSheetValue: PanSheetContextValue }
> {
setActiveScrollView = ref => {
if (ref === null) {
this.setState({
panSheetValue: {
...this.state.panSheetValue,
panScrollTag: null
}
});
} else if (ref?.current instanceof FastList) {
this.setActiveScrollView(ref.current.getScrollView());
} else if (typeof ref?.current?.getNode === "function") {
this.setActiveScrollView(ref.current.getNode());
} else if (typeof ref?.current !== "undefined") {
console.log(
"GOT",
(ref.current as ScrollViewType)?.scrollResponderGetScrollableNode()
);
this.setState({
panSheetValue: {
...this.state.panSheetValue,
panScrollTag: (ref.current as ScrollViewType)?.scrollResponderGetScrollableNode()
}
});
} else if ((ref as ScrollViewType)?.scrollResponderGetScrollableNode()) {
console.log(
"GOT IT!",
(ref as ScrollViewType)?.scrollResponderGetScrollableNode()
);
this.setState({
panSheetValue: {
...this.state.panSheetValue,
panScrollTag: (ref as ScrollViewType)?.scrollResponderGetScrollableNode()
}
});
} else {
this.setState({
panSheetValue: {
...this.state.panSheetValue,
panScrollTag: null
}
});
}
};
static defaultProps = {
defaultPresentationState: PanSheetViewSize.short
};
constructor(props) {
super(props);
this.state = {
panSheetValue: {
size: props.defaultPresentationState,
setActiveScrollView: this.setActiveScrollView,
panScrollTag: null,
setSize: this.setSize
}
};
}
containerRef = React.createRef();
containerTag: number;
nativePanSheetView = React.createRef<View>();
_shouldSetResponder = () => false;
componentDidMount() {}
handleTransition = (
event: NativeSyntheticEvent<{
from: PanSheetViewSize;
to: PanSheetViewSize;
}>
) => {
if (event.nativeEvent.to === this.state.panSheetValue.size) {
return;
}
this.setState({
panSheetValue: {
...this.state.panSheetValue,
size: event.nativeEvent.to
}
});
};
setSize = (size: PanSheetViewSize) => {
if (!this.nativePanSheetView.current) {
return;
}
if (this.state.panSheetValue.size !== size) {
this.setState({
panSheetValue: {
...this.state.panSheetValue,
size
}
});
}
transitionPanSheetView(
findNodeHandle(this.nativePanSheetView.current),
size
);
};
dismiss = () => {
transitionPanSheetView(
findNodeHandle(this.nativePanSheetView.current),
"dismiss"
);
};
setNativeProps = props => {
this.nativePanSheetView.current.setNativeProps(props);
};
render() {
return (
<NativePanSheetView
screenOffset={this.props.screenOffset}
screenMinY={this.props.screenMinY}
ref={this.nativePanSheetView}
longHeight={this.props.longHeight}
shortHeight={this.props.shortHeight}
headerTag={this.props.headerTag}
// onStartShouldSetResponder={this._shouldSetResponder}
onTransition={this.handleTransition}
didAppear={this.props.didAppear}
defaultPresentationState={this.props.defaultPresentationState}
onDismiss={this.props.onDismiss}
onTransition={this.handleTransition}
style={styles.modal}
onWillDismiss={this.props.onWillDismiss}
panScrollTag={this.state.panSheetValue.panScrollTag}
>
<PanSheetContext.Provider value={this.state.panSheetValue}>
<ScrollView.Context.Provider value={null}>
<View style={styles.container}>{this.props.children}</View>
</ScrollView.Context.Provider>
</PanSheetContext.Provider>
</NativePanSheetView>
);
}
}
const styles = StyleSheet.create({
modal: {
position: "absolute",
overflow: "visible"
},
container: {
/* $FlowFixMe(>=0.111.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.111 was deployed. To see the error, delete this
* comment and run Flow. */
left: 0,
top: 0,
overflow: "visible",
width: "100%",
height: "100%"
}
});L-U-C-K-Y and romanonthego
Metadata
Metadata
Assignees
Labels
No labels