progress
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
require "json"
|
||||||
|
|
||||||
|
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
||||||
|
|
||||||
|
Pod::Spec.new do |s|
|
||||||
|
s.name = "ScrollForwarder"
|
||||||
|
s.version = package["version"]
|
||||||
|
s.summary = package["description"]
|
||||||
|
s.homepage = package["homepage"]
|
||||||
|
s.license = package["license"]
|
||||||
|
s.authors = package["author"]
|
||||||
|
|
||||||
|
s.platforms = { :ios => min_ios_version_supported }
|
||||||
|
s.source = { :git => ".git", :tag => "#{s.version}" }
|
||||||
|
|
||||||
|
s.source_files = "ios/**/*.{h,m,mm,cpp}"
|
||||||
|
s.private_header_files = "ios/**/*.h"
|
||||||
|
|
||||||
|
install_modules_dependencies(s)
|
||||||
|
end
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#import <React/RCTViewComponentView.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#ifndef ScrollForwarderViewNativeComponent_h
|
||||||
|
#define ScrollForwarderViewNativeComponent_h
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface ScrollForwarderView : RCTViewComponentView
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
#endif /* ScrollForwarderViewNativeComponent_h */
|
||||||
@@ -0,0 +1,401 @@
|
|||||||
|
#import "ScrollForwarderView.h"
|
||||||
|
|
||||||
|
#import <React/RCTEnhancedScrollView.h>
|
||||||
|
#import <React/RCTScrollViewComponentView.h>
|
||||||
|
#import <React/RCTRefreshControl.h>
|
||||||
|
#import <React/RCTPullToRefreshViewComponentView.h>
|
||||||
|
#import <react/renderer/components/ScrollForwarderViewSpec/ComponentDescriptors.h>
|
||||||
|
#import <react/renderer/components/ScrollForwarderViewSpec/EventEmitters.h>
|
||||||
|
#import <react/renderer/components/ScrollForwarderViewSpec/Props.h>
|
||||||
|
#import <react/renderer/components/ScrollForwarderViewSpec/RCTComponentViewHelpers.h>
|
||||||
|
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
|
|
||||||
|
using namespace facebook::react;
|
||||||
|
|
||||||
|
static const CGFloat kPullThreshold = 130.0;
|
||||||
|
static const CGFloat kDampingFactor = 0.55;
|
||||||
|
static const CGFloat kMaxVelocity = 5000.0;
|
||||||
|
static const CGFloat kVelocityDecay = 0.9875;
|
||||||
|
static const CGFloat kMinimumVelocity = 5.0;
|
||||||
|
|
||||||
|
@interface ScrollForwarderView () <RCTScrollForwarderViewViewProtocol, UIGestureRecognizerDelegate>
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ScrollForwarderView {
|
||||||
|
UIView * _view;
|
||||||
|
|
||||||
|
NSArray<UIGestureRecognizer *> * _cancelGestureRecognizers;
|
||||||
|
RCTScrollViewComponentView * _svcv;
|
||||||
|
CGPoint _initialOffset;
|
||||||
|
|
||||||
|
CADisplayLink * _displayLink;
|
||||||
|
CGFloat _currentVelocity;
|
||||||
|
CGFloat _accumulatedTranslation;
|
||||||
|
|
||||||
|
bool _didImpact;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
||||||
|
{
|
||||||
|
return concreteComponentDescriptorProvider<ScrollForwarderViewComponentDescriptor>();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:frame]) {
|
||||||
|
static const auto defaultProps = std::make_shared<const ScrollForwarderViewProps>();
|
||||||
|
_props = defaultProps;
|
||||||
|
|
||||||
|
_view = [[UIView alloc] init];
|
||||||
|
|
||||||
|
UIPanGestureRecognizer *pg = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
|
||||||
|
pg.delegate = self;
|
||||||
|
[self addGestureRecognizer:pg];
|
||||||
|
|
||||||
|
UITapGestureRecognizer *tg = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
|
||||||
|
[tg setEnabled:true];
|
||||||
|
tg.delegate = self;
|
||||||
|
|
||||||
|
UILongPressGestureRecognizer *lpg = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
|
||||||
|
[lpg setMinimumPressDuration:0.01];
|
||||||
|
[lpg setEnabled:true];
|
||||||
|
lpg.delegate = self;
|
||||||
|
|
||||||
|
NSArray<UIGestureRecognizer *> *cancelGestureRecognizers = [NSArray arrayWithObjects:lpg, tg, nil];
|
||||||
|
_cancelGestureRecognizers = cancelGestureRecognizers;
|
||||||
|
|
||||||
|
self.contentView = _view;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[self stopAnimation];
|
||||||
|
_svcv = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareForRecycle
|
||||||
|
{
|
||||||
|
[super prepareForRecycle];
|
||||||
|
[self stopAnimation];
|
||||||
|
_svcv = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Props
|
||||||
|
|
||||||
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
|
{
|
||||||
|
const auto &oldViewProps = *std::static_pointer_cast<ScrollForwarderViewProps const>(_props);
|
||||||
|
const auto &newViewProps = *std::static_pointer_cast<ScrollForwarderViewProps const>(props);
|
||||||
|
|
||||||
|
if (oldViewProps.scrollViewTag != newViewProps.scrollViewTag) {
|
||||||
|
[self tryFindScrollView];
|
||||||
|
}
|
||||||
|
|
||||||
|
[super updateProps:props oldProps:oldProps];
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - UIGestureRecognizerDelegate
|
||||||
|
|
||||||
|
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
|
||||||
|
{
|
||||||
|
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
|
||||||
|
{
|
||||||
|
if (![gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIPanGestureRecognizer *pg = (UIPanGestureRecognizer *)gestureRecognizer;
|
||||||
|
CGPoint velocity = [pg velocityInView:self];
|
||||||
|
|
||||||
|
return fabs(velocity.y) > fabs(velocity.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||||
|
{
|
||||||
|
[self stopAnimation];
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Scroll Forwarding
|
||||||
|
|
||||||
|
- (void)removeCancelGestureRecognizers
|
||||||
|
{
|
||||||
|
if (!_svcv) return;
|
||||||
|
for (UIGestureRecognizer *gr in _cancelGestureRecognizers) {
|
||||||
|
[_svcv.scrollView removeGestureRecognizer:gr];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addCancelGestureRecognizers
|
||||||
|
{
|
||||||
|
if (!_svcv) return;
|
||||||
|
for (UIGestureRecognizer *gr in _cancelGestureRecognizers) {
|
||||||
|
[_svcv.scrollView addGestureRecognizer:gr];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)enableCancelGestureRecognizers
|
||||||
|
{
|
||||||
|
for (UIGestureRecognizer *gr in _cancelGestureRecognizers) {
|
||||||
|
[gr setEnabled:true];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)disableCancelGestureRecognizers
|
||||||
|
{
|
||||||
|
for (UIGestureRecognizer *gr in _cancelGestureRecognizers) {
|
||||||
|
[gr setEnabled:false];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollToOffset:(CGPoint)offset animated:(bool)animated
|
||||||
|
{
|
||||||
|
if (!_svcv) return;
|
||||||
|
[_svcv scrollToOffset:offset animated:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopAnimation
|
||||||
|
{
|
||||||
|
[self disableCancelGestureRecognizers];
|
||||||
|
if (_displayLink) {
|
||||||
|
[_displayLink invalidate];
|
||||||
|
_displayLink = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)handlePan:(UIPanGestureRecognizer *)gesture {
|
||||||
|
if (!_svcv) return;
|
||||||
|
|
||||||
|
UIScrollView *sv = _svcv.scrollView;
|
||||||
|
|
||||||
|
CGPoint translation = [gesture translationInView:self];
|
||||||
|
|
||||||
|
if (gesture.state == UIGestureRecognizerStateBegan) {
|
||||||
|
if (sv.contentOffset.y < 0) {
|
||||||
|
CGPoint newOffset = CGPointMake(sv.contentOffset.x, 0);
|
||||||
|
sv.contentOffset = newOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
_initialOffset = sv.contentOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gesture.state == UIGestureRecognizerStateChanged) {
|
||||||
|
CGPoint newOffset = CGPointMake(sv.contentOffset.x, [self dampenOffset:(-translation.y + _initialOffset.y)]);
|
||||||
|
sv.contentOffset = newOffset;
|
||||||
|
|
||||||
|
if (sv.contentOffset.y <= -kPullThreshold && !_didImpact) {
|
||||||
|
UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
|
||||||
|
[generator impactOccurred];
|
||||||
|
_didImpact = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gesture.state == UIGestureRecognizerStateEnded) {
|
||||||
|
CGPoint velocity = [gesture velocityInView:self];
|
||||||
|
_didImpact = false;
|
||||||
|
|
||||||
|
if (sv.contentOffset.y <= -kPullThreshold) {
|
||||||
|
[self refresh];
|
||||||
|
// if ([_svcv.scrollView.refreshControl isKindOfClass:[RCTRefreshControl class]]) {
|
||||||
|
// RCTRefreshControl *refreshCtrl = (RCTRefreshControl *) _svcv.scrollView.refreshControl;
|
||||||
|
// [refreshCtrl forwarderBeginRefreshing];
|
||||||
|
// }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sv.contentOffset.y < 0) {
|
||||||
|
CGPoint newOffset = CGPointMake(sv.contentOffset.x, 0);
|
||||||
|
[self scrollToOffset:newOffset animated:true];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abs(velocity.y) < 250 && sv.contentOffset.y >= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self startDecayWithInitialTranslation:translation.y velocity:velocity.y];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)dampenOffset:(CGFloat)offset
|
||||||
|
{
|
||||||
|
if (offset < 0) {
|
||||||
|
return offset - (offset * kDampingFactor);
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)handleTap:(UITapGestureRecognizer *)gesture {
|
||||||
|
[self stopAnimation];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture {
|
||||||
|
[self stopAnimation];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startDecayWithInitialTranslation:(CGFloat)translation velocity:(CGFloat)startVelocity
|
||||||
|
{
|
||||||
|
if (!_svcv) return;
|
||||||
|
|
||||||
|
startVelocity = MAX(-kMaxVelocity, MIN(kMaxVelocity, startVelocity));
|
||||||
|
_currentVelocity = startVelocity;
|
||||||
|
_accumulatedTranslation = -translation;
|
||||||
|
|
||||||
|
[self enableCancelGestureRecognizers];
|
||||||
|
|
||||||
|
[_displayLink invalidate];
|
||||||
|
|
||||||
|
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDecayStep:)];
|
||||||
|
|
||||||
|
link.preferredFramesPerSecond = 60;
|
||||||
|
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||||
|
_displayLink = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)handleDecayStep:(CADisplayLink *)link
|
||||||
|
{
|
||||||
|
_currentVelocity *= kVelocityDecay;
|
||||||
|
|
||||||
|
CGFloat delta = -_currentVelocity / link.preferredFramesPerSecond;
|
||||||
|
_accumulatedTranslation += delta;
|
||||||
|
|
||||||
|
CGFloat rawY = _accumulatedTranslation + _initialOffset.y;
|
||||||
|
CGFloat nextY = rawY > 0 ? rawY : 0;
|
||||||
|
|
||||||
|
CGPoint newOffset = CGPointMake(
|
||||||
|
_svcv.scrollView.contentOffset.x,
|
||||||
|
nextY
|
||||||
|
);
|
||||||
|
_svcv.scrollView.contentOffset = newOffset;
|
||||||
|
|
||||||
|
if (fabs(_currentVelocity) < kMinimumVelocity || nextY <= 0) {
|
||||||
|
[link invalidate];
|
||||||
|
_displayLink = nil;
|
||||||
|
[self disableCancelGestureRecognizers];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use this component on profile pages. The screne consists of a header component, a scrollview with buttons to
|
||||||
|
* switch between profile tabs, and a pager view (RNCPagerViewComponentView). Both the header and the tab bar are
|
||||||
|
* inside the same RCTViewComponentView. The view heirarchy looks something like this:
|
||||||
|
* - RCTViewComponentView
|
||||||
|
* -- RNCPagerViewComponentView
|
||||||
|
* ----- (Many views deep) RCTScrollViewComponentView
|
||||||
|
* ------ RCTEnhancedScrollView
|
||||||
|
* -- RCTViewComponentView
|
||||||
|
* --- RCTViewComponentView
|
||||||
|
* ---- ScrollForwarderView
|
||||||
|
* --- RCTScrollViewComponentView
|
||||||
|
* ---- RCTEnhancedScrollView
|
||||||
|
*
|
||||||
|
* We want to find that RCTScrollViewComponentView inside of the RNCPagerViewComponentView. To achieve this, we can
|
||||||
|
* use self.superview.superview.superview to get to the root RCTViewComponentView, find the RNCPagerViewComponentView,
|
||||||
|
* then iterate through that view's subviews until we find a RCTScrollViewComponentView.
|
||||||
|
*
|
||||||
|
* This isn't great, because if we reorder the React components, we'll need to update this logic. There's probably
|
||||||
|
* an easier way to achieve this, similar to how we used to do it in Paper (ie, get the scroll view's tag and find that),
|
||||||
|
* but this also comes with some benefits, eg being able to reduce a lot of the logic in the JS code and just find the
|
||||||
|
* scrollview when subviews change.
|
||||||
|
*/
|
||||||
|
- (void)tryFindScrollView
|
||||||
|
{
|
||||||
|
[self removeCancelGestureRecognizers];
|
||||||
|
|
||||||
|
// The root RCTViewComponentView
|
||||||
|
UIView *rootView = self.superview.superview.superview;
|
||||||
|
UIView *pagerView;
|
||||||
|
|
||||||
|
NSString *targetClsName = @"RNCPagerViewComponentView";
|
||||||
|
Class targetCls = NSClassFromString(targetClsName);
|
||||||
|
|
||||||
|
for (UIView *subview in rootView.subviews) {
|
||||||
|
if ([subview isKindOfClass:targetCls]) {
|
||||||
|
pagerView = subview;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pagerView) return;
|
||||||
|
|
||||||
|
RCTScrollViewComponentView *svcv = [self findRTCScrollViewComponentViewInView:pagerView];
|
||||||
|
|
||||||
|
if (!svcv) return;
|
||||||
|
|
||||||
|
_svcv = svcv;
|
||||||
|
[self addCancelGestureRecognizers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (RCTScrollViewComponentView *)findRTCScrollViewComponentViewInView:(UIView *)view
|
||||||
|
{
|
||||||
|
for (UIView *subview in view.subviews) {
|
||||||
|
if ([subview isKindOfClass:[RCTScrollViewComponentView class]]) {
|
||||||
|
RCTScrollViewComponentView *svcv = (RCTScrollViewComponentView *) subview;
|
||||||
|
return svcv;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCTScrollViewComponentView *svcv = [self findRTCScrollViewComponentViewInView:subview];
|
||||||
|
if (svcv) return svcv;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) refresh
|
||||||
|
{
|
||||||
|
// if ([_svcv.scrollView.refreshControl isKindOfClass:[RCTPullToRefreshViewComponentView class]]) {
|
||||||
|
// RCTPullToRefreshViewComponentView *refreshView = (RCTPullToRefreshViewComponentView *) _svcv.scrollView.refreshControl;
|
||||||
|
// [refreshView beginRefreshingProgrammatically];
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<RCTComponentViewProtocol> ScrollForwarderViewCls(void)
|
||||||
|
{
|
||||||
|
return ScrollForwarderView.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
//- (void)forwarderBeginRefreshing
|
||||||
|
//{
|
||||||
|
// _refreshingProgrammatically = NO;
|
||||||
|
//
|
||||||
|
// [self sizeToFit];
|
||||||
|
//
|
||||||
|
// if (!self.scrollView) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// UIScrollView *scrollView = (UIScrollView *)self.scrollView;
|
||||||
|
//
|
||||||
|
// [UIView animateWithDuration:0.3
|
||||||
|
// delay:0
|
||||||
|
// options:UIViewAnimationOptionBeginFromCurrentState
|
||||||
|
// animations:^(void) {
|
||||||
|
// // Whenever we call this method, the scrollview will always be at a position of
|
||||||
|
// // -130 or less. Scrolling back to -65 simulates the default behavior of RCTRefreshControl
|
||||||
|
// [scrollView setContentOffset:CGPointMake(0, -65)];
|
||||||
|
// }
|
||||||
|
// completion:^(__unused BOOL finished) {
|
||||||
|
// [super beginRefreshing];
|
||||||
|
// [self setCurrentRefreshingState:super.refreshing];
|
||||||
|
//
|
||||||
|
// if (self->_onRefresh) {
|
||||||
|
// self->_onRefresh(nil);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ];
|
||||||
|
//}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#import <React/RCTViewManager.h>
|
||||||
|
#import <React/RCTUIManager.h>
|
||||||
|
#import "RCTBridge.h"
|
||||||
|
|
||||||
|
@interface ScrollForwarderViewManager : RCTViewManager
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ScrollForwarderViewManager
|
||||||
|
|
||||||
|
RCT_EXPORT_MODULE(ScrollForwarderView)
|
||||||
|
|
||||||
|
- (UIView *)view
|
||||||
|
{
|
||||||
|
return [[UIView alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(scrollViewTag, NSNumber)
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "react-native-scroll-forwarder",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "Scroll forwarder module for Bluesky profile headers",
|
||||||
|
"main": "src/index",
|
||||||
|
"codegenConfig": {
|
||||||
|
"name": "ScrollForwarderViewSpec",
|
||||||
|
"type": "all",
|
||||||
|
"jsSrcsDir": "src"
|
||||||
|
},
|
||||||
|
"author": "Hailey <me@haileyok.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "#readme",
|
||||||
|
"create-react-native-library": {
|
||||||
|
"languages": "kotlin-objc",
|
||||||
|
"type": "fabric-view",
|
||||||
|
"version": "0.50.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import {
|
||||||
|
default as NativeScrollForwarderView,
|
||||||
|
NativeProps,
|
||||||
|
} from './ScrollForwarderViewNativeComponent'
|
||||||
|
|
||||||
|
export function ScrollForwarderView({children, ...rest}: NativeProps) {
|
||||||
|
return (
|
||||||
|
<NativeScrollForwarderView {...rest}>{children}</NativeScrollForwarderView>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import {NativeProps} from './ScrollForwarderViewNativeComponent'
|
||||||
|
|
||||||
|
export function ScrollForwarderView({children}: NativeProps) {
|
||||||
|
return children
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'
|
||||||
|
import type {ViewProps} from 'react-native'
|
||||||
|
import {Int32} from 'react-native/Libraries/Types/CodegenTypes'
|
||||||
|
|
||||||
|
export interface NativeProps extends ViewProps {
|
||||||
|
scrollViewTag?: Int32
|
||||||
|
}
|
||||||
|
|
||||||
|
export default codegenNativeComponent<NativeProps>('ScrollForwarderView')
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export {ScrollForwarderView} from './ScrollForwarderView'
|
||||||
|
export * from './ScrollForwarderViewNativeComponent'
|
||||||
+2
-1
@@ -215,7 +215,8 @@
|
|||||||
"tlds": "^1.234.0",
|
"tlds": "^1.234.0",
|
||||||
"tldts": "^6.1.46",
|
"tldts": "^6.1.46",
|
||||||
"zeego": "^1.6.2",
|
"zeego": "^1.6.2",
|
||||||
"zod": "^3.20.2"
|
"zod": "^3.20.2",
|
||||||
|
"react-native-scroll-forwarder": "link:./modules/react-native-scroll-forwarder"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@atproto/dev-env": "^0.3.129",
|
"@atproto/dev-env": "^0.3.129",
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import {ScreenHider} from '#/components/moderation/ScreenHider'
|
|||||||
import {ProfileStarterPacks} from '#/components/StarterPack/ProfileStarterPacks'
|
import {ProfileStarterPacks} from '#/components/StarterPack/ProfileStarterPacks'
|
||||||
import {navigate} from '#/Navigation'
|
import {navigate} from '#/Navigation'
|
||||||
import {ExpoScrollForwarderView} from '../../../modules/expo-scroll-forwarder'
|
import {ExpoScrollForwarderView} from '../../../modules/expo-scroll-forwarder'
|
||||||
|
import {ScrollForwarderView} from 'modules/react-native-scroll-forwarder/src'
|
||||||
|
|
||||||
interface SectionRef {
|
interface SectionRef {
|
||||||
scrollToTop: () => void
|
scrollToTop: () => void
|
||||||
@@ -343,7 +344,7 @@ function ProfileScreenLoaded({
|
|||||||
setMinimumHeight: (height: number) => void
|
setMinimumHeight: (height: number) => void
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<ExpoScrollForwarderView scrollViewTag={scrollViewTag}>
|
<ScrollForwarderView scrollViewTag={scrollViewTag}>
|
||||||
<ProfileHeader
|
<ProfileHeader
|
||||||
profile={profile}
|
profile={profile}
|
||||||
labeler={labelerInfo}
|
labeler={labelerInfo}
|
||||||
@@ -353,7 +354,7 @@ function ProfileScreenLoaded({
|
|||||||
isPlaceholderProfile={showPlaceholder}
|
isPlaceholderProfile={showPlaceholder}
|
||||||
setMinimumHeight={setMinimumHeight}
|
setMinimumHeight={setMinimumHeight}
|
||||||
/>
|
/>
|
||||||
</ExpoScrollForwarderView>
|
</ScrollForwarderView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16900,6 +16900,10 @@ react-native-screens@~4.10.0:
|
|||||||
react-freeze "^1.0.0"
|
react-freeze "^1.0.0"
|
||||||
warn-once "^0.1.0"
|
warn-once "^0.1.0"
|
||||||
|
|
||||||
|
"react-native-scroll-forwarder@link:./modules/react-native-scroll-forwarder":
|
||||||
|
version "0.0.0"
|
||||||
|
uid ""
|
||||||
|
|
||||||
react-native-svg@15.11.2:
|
react-native-svg@15.11.2:
|
||||||
version "15.11.2"
|
version "15.11.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-15.11.2.tgz#7540e8e1eabc4dcd3b1e35ada5a1d9f1b96d37c4"
|
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-15.11.2.tgz#7540e8e1eabc4dcd3b1e35ada5a1d9f1b96d37c4"
|
||||||
|
|||||||
Reference in New Issue
Block a user