first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,566 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "BaseScrollViewProps.h"
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/renderer/components/scrollview/conversions.h>
#include <react/renderer/core/graphicsConversions.h>
#include <react/renderer/debug/debugStringConvertibleUtils.h>
#include <react/renderer/core/propsConversions.h>
namespace facebook::react {
// TODO (T28334063): Consider for codegen.
BaseScrollViewProps::BaseScrollViewProps(
const PropsParserContext& context,
const BaseScrollViewProps& sourceProps,
const RawProps& rawProps)
: ViewProps(context, sourceProps, rawProps),
alwaysBounceHorizontal(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.alwaysBounceHorizontal
: convertRawProp(
context,
rawProps,
"alwaysBounceHorizontal",
sourceProps.alwaysBounceHorizontal,
{})),
alwaysBounceVertical(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.alwaysBounceVertical
: convertRawProp(
context,
rawProps,
"alwaysBounceVertical",
sourceProps.alwaysBounceVertical,
{})),
bounces(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.bounces
: convertRawProp(
context,
rawProps,
"bounces",
sourceProps.bounces,
true)),
bouncesZoom(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.bouncesZoom
: convertRawProp(
context,
rawProps,
"bouncesZoom",
sourceProps.bouncesZoom,
true)),
canCancelContentTouches(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.canCancelContentTouches
: convertRawProp(
context,
rawProps,
"canCancelContentTouches",
sourceProps.canCancelContentTouches,
true)),
centerContent(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.centerContent
: convertRawProp(
context,
rawProps,
"centerContent",
sourceProps.centerContent,
{})),
automaticallyAdjustContentInsets(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.automaticallyAdjustContentInsets
: convertRawProp(
context,
rawProps,
"automaticallyAdjustContentInsets",
sourceProps.automaticallyAdjustContentInsets,
{})),
automaticallyAdjustsScrollIndicatorInsets(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.automaticallyAdjustsScrollIndicatorInsets
: convertRawProp(
context,
rawProps,
"automaticallyAdjustsScrollIndicatorInsets",
sourceProps.automaticallyAdjustsScrollIndicatorInsets,
true)),
automaticallyAdjustKeyboardInsets(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.automaticallyAdjustKeyboardInsets
: convertRawProp(
context,
rawProps,
"automaticallyAdjustKeyboardInsets",
sourceProps.automaticallyAdjustKeyboardInsets,
false)),
decelerationRate(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.decelerationRate
: convertRawProp(
context,
rawProps,
"decelerationRate",
sourceProps.decelerationRate,
(Float)0.998)),
endDraggingSensitivityMultiplier(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.endDraggingSensitivityMultiplier
: convertRawProp(
context,
rawProps,
"endDraggingSensitivityMultiplier",
sourceProps.endDraggingSensitivityMultiplier,
(Float)1)),
directionalLockEnabled(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.directionalLockEnabled
: convertRawProp(
context,
rawProps,
"directionalLockEnabled",
sourceProps.directionalLockEnabled,
{})),
indicatorStyle(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.indicatorStyle
: convertRawProp(
context,
rawProps,
"indicatorStyle",
sourceProps.indicatorStyle,
{})),
keyboardDismissMode(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.keyboardDismissMode
: convertRawProp(
context,
rawProps,
"keyboardDismissMode",
sourceProps.keyboardDismissMode,
{})),
maintainVisibleContentPosition(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.maintainVisibleContentPosition
: convertRawProp(
context,
rawProps,
"maintainVisibleContentPosition",
sourceProps.maintainVisibleContentPosition,
{})),
maximumZoomScale(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.maximumZoomScale
: convertRawProp(
context,
rawProps,
"maximumZoomScale",
sourceProps.maximumZoomScale,
(Float)1.0)),
minimumZoomScale(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.minimumZoomScale
: convertRawProp(
context,
rawProps,
"minimumZoomScale",
sourceProps.minimumZoomScale,
(Float)1.0)),
scrollEnabled(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.scrollEnabled
: convertRawProp(
context,
rawProps,
"scrollEnabled",
sourceProps.scrollEnabled,
true)),
pagingEnabled(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.pagingEnabled
: convertRawProp(
context,
rawProps,
"pagingEnabled",
sourceProps.pagingEnabled,
{})),
pinchGestureEnabled(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.pinchGestureEnabled
: convertRawProp(
context,
rawProps,
"pinchGestureEnabled",
sourceProps.pinchGestureEnabled,
true)),
scrollsToTop(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.scrollsToTop
: convertRawProp(
context,
rawProps,
"scrollsToTop",
sourceProps.scrollsToTop,
true)),
showsHorizontalScrollIndicator(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.showsHorizontalScrollIndicator
: convertRawProp(
context,
rawProps,
"showsHorizontalScrollIndicator",
sourceProps.showsHorizontalScrollIndicator,
true)),
showsVerticalScrollIndicator(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.showsVerticalScrollIndicator
: convertRawProp(
context,
rawProps,
"showsVerticalScrollIndicator",
sourceProps.showsVerticalScrollIndicator,
true)),
persistentScrollbar(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.persistentScrollbar
: convertRawProp(
context,
rawProps,
"persistentScrollbar",
sourceProps.persistentScrollbar,
true)),
horizontal(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.horizontal
: convertRawProp(
context,
rawProps,
"horizontal",
sourceProps.horizontal,
true)),
scrollEventThrottle(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.scrollEventThrottle
: convertRawProp(
context,
rawProps,
"scrollEventThrottle",
sourceProps.scrollEventThrottle,
{})),
zoomScale(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.zoomScale
: convertRawProp(
context,
rawProps,
"zoomScale",
sourceProps.zoomScale,
(Float)1.0)),
contentInset(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.contentInset
: convertRawProp(
context,
rawProps,
"contentInset",
sourceProps.contentInset,
{})),
contentOffset(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.contentOffset
: convertRawProp(
context,
rawProps,
"contentOffset",
sourceProps.contentOffset,
{})),
scrollIndicatorInsets(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.scrollIndicatorInsets
: convertRawProp(
context,
rawProps,
"scrollIndicatorInsets",
sourceProps.scrollIndicatorInsets,
{})),
snapToInterval(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.snapToInterval
: convertRawProp(
context,
rawProps,
"snapToInterval",
sourceProps.snapToInterval,
{})),
snapToAlignment(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.snapToAlignment
: convertRawProp(
context,
rawProps,
"snapToAlignment",
sourceProps.snapToAlignment,
{})),
disableIntervalMomentum(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.disableIntervalMomentum
: convertRawProp(
context,
rawProps,
"disableIntervalMomentum",
sourceProps.disableIntervalMomentum,
{})),
snapToOffsets(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.snapToOffsets
: convertRawProp(
context,
rawProps,
"snapToOffsets",
sourceProps.snapToOffsets,
{})),
snapToStart(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.snapToStart
: convertRawProp(
context,
rawProps,
"snapToStart",
sourceProps.snapToStart,
true)),
snapToEnd(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.snapToEnd
: convertRawProp(
context,
rawProps,
"snapToEnd",
sourceProps.snapToEnd,
true)),
contentInsetAdjustmentBehavior(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.contentInsetAdjustmentBehavior
: convertRawProp(
context,
rawProps,
"contentInsetAdjustmentBehavior",
sourceProps.contentInsetAdjustmentBehavior,
{ContentInsetAdjustmentBehavior::Never})),
scrollToOverflowEnabled(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.scrollToOverflowEnabled
: convertRawProp(
context,
rawProps,
"scrollToOverflowEnabled",
sourceProps.scrollToOverflowEnabled,
{})),
isInvertedVirtualizedList(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.isInvertedVirtualizedList
: convertRawProp(
context,
rawProps,
"isInvertedVirtualizedList",
sourceProps.isInvertedVirtualizedList,
{})) {}
void BaseScrollViewProps::setProp(
const PropsParserContext& context,
RawPropsPropNameHash hash,
const char* propName,
const RawValue& value) {
// All Props structs setProp methods must always, unconditionally,
// call all super::setProp methods, since multiple structs may
// reuse the same values.
ViewProps::setProp(context, hash, propName, value);
static auto defaults = BaseScrollViewProps{};
switch (hash) {
RAW_SET_PROP_SWITCH_CASE_BASIC(alwaysBounceHorizontal);
RAW_SET_PROP_SWITCH_CASE_BASIC(alwaysBounceVertical);
RAW_SET_PROP_SWITCH_CASE_BASIC(bounces);
RAW_SET_PROP_SWITCH_CASE_BASIC(bouncesZoom);
RAW_SET_PROP_SWITCH_CASE_BASIC(canCancelContentTouches);
RAW_SET_PROP_SWITCH_CASE_BASIC(centerContent);
RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustContentInsets);
RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustsScrollIndicatorInsets);
RAW_SET_PROP_SWITCH_CASE_BASIC(decelerationRate);
RAW_SET_PROP_SWITCH_CASE_BASIC(directionalLockEnabled);
RAW_SET_PROP_SWITCH_CASE_BASIC(indicatorStyle);
RAW_SET_PROP_SWITCH_CASE_BASIC(keyboardDismissMode);
RAW_SET_PROP_SWITCH_CASE_BASIC(maintainVisibleContentPosition);
RAW_SET_PROP_SWITCH_CASE_BASIC(maximumZoomScale);
RAW_SET_PROP_SWITCH_CASE_BASIC(minimumZoomScale);
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollEnabled);
RAW_SET_PROP_SWITCH_CASE_BASIC(endDraggingSensitivityMultiplier);
RAW_SET_PROP_SWITCH_CASE_BASIC(pagingEnabled);
RAW_SET_PROP_SWITCH_CASE_BASIC(pinchGestureEnabled);
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollsToTop);
RAW_SET_PROP_SWITCH_CASE_BASIC(showsHorizontalScrollIndicator);
RAW_SET_PROP_SWITCH_CASE_BASIC(showsVerticalScrollIndicator);
RAW_SET_PROP_SWITCH_CASE_BASIC(persistentScrollbar);
RAW_SET_PROP_SWITCH_CASE_BASIC(horizontal);
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollEventThrottle);
RAW_SET_PROP_SWITCH_CASE_BASIC(zoomScale);
RAW_SET_PROP_SWITCH_CASE_BASIC(contentInset);
RAW_SET_PROP_SWITCH_CASE_BASIC(contentOffset);
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollIndicatorInsets);
RAW_SET_PROP_SWITCH_CASE_BASIC(snapToInterval);
RAW_SET_PROP_SWITCH_CASE_BASIC(snapToAlignment);
RAW_SET_PROP_SWITCH_CASE_BASIC(disableIntervalMomentum);
RAW_SET_PROP_SWITCH_CASE_BASIC(snapToOffsets);
RAW_SET_PROP_SWITCH_CASE_BASIC(snapToStart);
RAW_SET_PROP_SWITCH_CASE_BASIC(snapToEnd);
RAW_SET_PROP_SWITCH_CASE_BASIC(contentInsetAdjustmentBehavior);
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollToOverflowEnabled);
RAW_SET_PROP_SWITCH_CASE_BASIC(isInvertedVirtualizedList);
}
}
#pragma mark - DebugStringConvertible
#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList BaseScrollViewProps::getDebugProps() const {
auto defaultScrollViewProps = BaseScrollViewProps{};
return ViewProps::getDebugProps() +
SharedDebugStringConvertibleList{
debugStringConvertibleItem(
"alwaysBounceHorizontal",
alwaysBounceHorizontal,
defaultScrollViewProps.alwaysBounceHorizontal),
debugStringConvertibleItem(
"alwaysBounceVertical",
alwaysBounceVertical,
defaultScrollViewProps.alwaysBounceVertical),
debugStringConvertibleItem(
"bounces", bounces, defaultScrollViewProps.bounces),
debugStringConvertibleItem(
"bouncesZoom", bouncesZoom, defaultScrollViewProps.bouncesZoom),
debugStringConvertibleItem(
"canCancelContentTouches",
canCancelContentTouches,
defaultScrollViewProps.canCancelContentTouches),
debugStringConvertibleItem(
"centerContent",
centerContent,
defaultScrollViewProps.centerContent),
debugStringConvertibleItem(
"automaticallyAdjustContentInsets",
automaticallyAdjustContentInsets,
defaultScrollViewProps.automaticallyAdjustContentInsets),
debugStringConvertibleItem(
"automaticallyAdjustsScrollIndicatorInsets",
automaticallyAdjustsScrollIndicatorInsets,
defaultScrollViewProps.automaticallyAdjustsScrollIndicatorInsets),
debugStringConvertibleItem(
"decelerationRate",
decelerationRate,
defaultScrollViewProps.decelerationRate),
debugStringConvertibleItem(
"directionalLockEnabled",
directionalLockEnabled,
defaultScrollViewProps.directionalLockEnabled),
debugStringConvertibleItem(
"indicatorStyle",
indicatorStyle,
defaultScrollViewProps.indicatorStyle),
debugStringConvertibleItem(
"keyboardDismissMode",
keyboardDismissMode,
defaultScrollViewProps.keyboardDismissMode),
debugStringConvertibleItem(
"maintainVisibleContentPosition",
maintainVisibleContentPosition,
defaultScrollViewProps.maintainVisibleContentPosition),
debugStringConvertibleItem(
"maximumZoomScale",
maximumZoomScale,
defaultScrollViewProps.maximumZoomScale),
debugStringConvertibleItem(
"minimumZoomScale",
minimumZoomScale,
defaultScrollViewProps.minimumZoomScale),
debugStringConvertibleItem(
"scrollEnabled",
scrollEnabled,
defaultScrollViewProps.scrollEnabled),
debugStringConvertibleItem(
"pagingEnabled",
pagingEnabled,
defaultScrollViewProps.pagingEnabled),
debugStringConvertibleItem(
"pinchGestureEnabled",
pinchGestureEnabled,
defaultScrollViewProps.pinchGestureEnabled),
debugStringConvertibleItem(
"scrollsToTop",
scrollsToTop,
defaultScrollViewProps.scrollsToTop),
debugStringConvertibleItem(
"showsHorizontalScrollIndicator",
showsHorizontalScrollIndicator,
defaultScrollViewProps.showsHorizontalScrollIndicator),
debugStringConvertibleItem(
"showsVerticalScrollIndicator",
showsVerticalScrollIndicator,
defaultScrollViewProps.showsVerticalScrollIndicator),
debugStringConvertibleItem(
"persistentScrollbar",
persistentScrollbar,
defaultScrollViewProps.persistentScrollbar),
debugStringConvertibleItem(
"horizontal", horizontal, defaultScrollViewProps.horizontal),
debugStringConvertibleItem(
"scrollEventThrottle",
scrollEventThrottle,
defaultScrollViewProps.scrollEventThrottle),
debugStringConvertibleItem(
"zoomScale", zoomScale, defaultScrollViewProps.zoomScale),
debugStringConvertibleItem(
"contentInset",
contentInset,
defaultScrollViewProps.contentInset),
debugStringConvertibleItem(
"contentOffset",
contentOffset,
defaultScrollViewProps.contentOffset),
debugStringConvertibleItem(
"scrollIndicatorInsets",
scrollIndicatorInsets,
defaultScrollViewProps.scrollIndicatorInsets),
debugStringConvertibleItem(
"snapToInterval",
snapToInterval,
defaultScrollViewProps.snapToInterval),
debugStringConvertibleItem(
"snapToAlignment",
snapToAlignment,
defaultScrollViewProps.snapToAlignment),
debugStringConvertibleItem(
"disableIntervalMomentum",
disableIntervalMomentum,
defaultScrollViewProps.disableIntervalMomentum),
debugStringConvertibleItem(
"snapToStart", snapToStart, defaultScrollViewProps.snapToStart),
debugStringConvertibleItem(
"snapToEnd", snapToEnd, defaultScrollViewProps.snapToEnd),
debugStringConvertibleItem(
"isInvertedVirtualizedList",
isInvertedVirtualizedList,
defaultScrollViewProps.isInvertedVirtualizedList)};
}
#endif
} // namespace facebook::react

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/scrollview/primitives.h>
#include <react/renderer/components/view/ViewProps.h>
#include <react/renderer/core/PropsParserContext.h>
#include <optional>
namespace facebook::react {
// TODO (T28334063): Consider for codegen.
class BaseScrollViewProps : public ViewProps {
public:
BaseScrollViewProps() = default;
BaseScrollViewProps(
const PropsParserContext &context,
const BaseScrollViewProps &sourceProps,
const RawProps &rawProps);
void
setProp(const PropsParserContext &context, RawPropsPropNameHash hash, const char *propName, const RawValue &value);
#pragma mark - Props
bool alwaysBounceHorizontal{};
bool alwaysBounceVertical{};
bool bounces{true};
bool bouncesZoom{true};
bool canCancelContentTouches{true};
bool centerContent{};
bool automaticallyAdjustContentInsets{};
bool automaticallyAdjustsScrollIndicatorInsets{true};
bool automaticallyAdjustKeyboardInsets{false};
Float decelerationRate{0.998f};
Float endDraggingSensitivityMultiplier{1};
bool directionalLockEnabled{};
ScrollViewIndicatorStyle indicatorStyle{};
ScrollViewKeyboardDismissMode keyboardDismissMode{};
std::optional<ScrollViewMaintainVisibleContentPosition> maintainVisibleContentPosition{};
Float maximumZoomScale{1.0f};
Float minimumZoomScale{1.0f};
bool scrollEnabled{true};
bool pagingEnabled{};
bool pinchGestureEnabled{true};
bool scrollsToTop{true};
bool showsHorizontalScrollIndicator{true};
bool showsVerticalScrollIndicator{true};
bool persistentScrollbar{false};
bool horizontal{false};
Float scrollEventThrottle{};
Float zoomScale{1.0f};
EdgeInsets contentInset{};
Point contentOffset{};
EdgeInsets scrollIndicatorInsets{};
Float snapToInterval{};
ScrollViewSnapToAlignment snapToAlignment{};
bool disableIntervalMomentum{false};
std::vector<Float> snapToOffsets{};
bool snapToStart{true};
bool snapToEnd{true};
ContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior{ContentInsetAdjustmentBehavior::Never};
bool scrollToOverflowEnabled{false};
bool isInvertedVirtualizedList{false};
#pragma mark - DebugStringConvertible
#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override;
#endif
};
} // namespace facebook::react

View File

@@ -0,0 +1,43 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/internal/react-native-platform-selector.cmake)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
react_native_android_selector(platform_SRC
platform/android/react/renderer/components/scrollview/*.cpp
platform/cxx/react/renderer/components/scrollview/*.cpp
)
file(GLOB rrc_scrollview_SRC CONFIGURE_DEPENDS *.cpp ${platform_SRC})
add_library(rrc_scrollview STATIC ${rrc_scrollview_SRC})
react_native_android_selector(platform_DIR
${CMAKE_CURRENT_SOURCE_DIR}/platform/android/
${CMAKE_CURRENT_SOURCE_DIR}/platform/cxx/)
target_include_directories(rrc_scrollview PUBLIC ${REACT_COMMON_DIR} . ${platform_DIR})
react_native_android_selector(platform_DIR_PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/platform/android/react/renderer/components/scrollview/
${CMAKE_CURRENT_SOURCE_DIR}/platform/cxx/react/renderer/components/scrollview/)
target_include_directories(rrc_scrollview PRIVATE ${platform_DIR_PRIVATE})
target_link_libraries(rrc_scrollview
glog
folly_runtime
glog_init
jsi
react_debug
react_renderer_core
react_renderer_debug
react_renderer_graphics
react_renderer_mapbuffer
rrc_view
yoga
)
target_compile_reactnative_options(rrc_scrollview PRIVATE)
target_compile_options(rrc_scrollview PRIVATE -Wpedantic)

View File

@@ -0,0 +1,133 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTDefines.h>
#import <React/RCTLog.h>
NS_ASSUME_NONNULL_BEGIN
@protocol RCTScrollViewProtocol <NSObject>
- (void)flashScrollIndicators;
- (void)scrollTo:(double)x y:(double)y animated:(BOOL)animated;
- (void)scrollToEnd:(BOOL)animated;
- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated;
@end
RCT_EXTERN inline void
RCTScrollViewHandleCommand(id<RCTScrollViewProtocol> componentView, const NSString *commandName, const NSArray *args)
{
if ([commandName isEqualToString:@"flashScrollIndicators"]) {
#if RCT_DEBUG
if ([args count] != 0) {
RCTLogError(
@"%@ command %@ received %d arguments, expected %d.", @"ScrollView", commandName, (int)[args count], 1);
return;
}
#endif
[componentView flashScrollIndicators];
return;
}
if ([commandName isEqualToString:@"scrollTo"]) {
#if RCT_DEBUG
if ([args count] != 3) {
RCTLogError(
@"%@ command %@ received %d arguments, expected %d.", @"ScrollView", commandName, (int)[args count], 3);
return;
}
#endif
NSObject *arg0 = args[0];
#if RCT_DEBUG
if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSNumber class], @"float", @"ScrollView", commandName, @"1st")) {
return;
}
#endif
NSObject *arg1 = args[1];
#if RCT_DEBUG
if (!RCTValidateTypeOfViewCommandArgument(arg1, [NSNumber class], @"float", @"ScrollView", commandName, @"2nd")) {
return;
}
#endif
NSObject *arg2 = args[2];
#if RCT_DEBUG
if (!RCTValidateTypeOfViewCommandArgument(arg2, [NSNumber class], @"boolean", @"ScrollView", commandName, @"3rd")) {
return;
}
#endif
double x = [(NSNumber *)arg0 doubleValue];
double y = [(NSNumber *)arg1 doubleValue];
BOOL animated = [(NSNumber *)arg2 boolValue];
[componentView scrollTo:x y:y animated:animated];
return;
}
if ([commandName isEqualToString:@"scrollToEnd"]) {
#if RCT_DEBUG
if ([args count] != 1) {
RCTLogError(
@"%@ command %@ received %d arguments, expected %d.", @"ScrollView", commandName, (int)[args count], 1);
return;
}
#endif
NSObject *arg0 = args[0];
#if RCT_DEBUG
if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSNumber class], @"boolean", @"ScrollView", commandName, @"1st")) {
return;
}
#endif
BOOL animated = [(NSNumber *)arg0 boolValue];
[componentView scrollToEnd:animated];
return;
}
if ([commandName isEqualToString:@"zoomToRect"]) {
#if RCT_DEBUG
if ([args count] != 2) {
RCTLogError(
@"%@ command %@ received %d arguments, expected %d.", @"ScrollView", commandName, (int)[args count], 2);
return;
}
#endif
NSObject *arg0 = args[0];
#if RCT_DEBUG
if (!RCTValidateTypeOfViewCommandArgument(
arg0, [NSDictionary class], @"dictionary", @"ScrollView", commandName, @"1st")) {
return;
}
#endif
NSDictionary *rectDict = (NSDictionary *)arg0;
NSNumber *x = rectDict[@"x"];
NSNumber *y = rectDict[@"y"];
NSNumber *width = rectDict[@"width"];
NSNumber *height = rectDict[@"height"];
CGRect rect = CGRectMake(x.doubleValue, y.doubleValue, width.doubleValue, height.doubleValue);
NSObject *arg1 = args[1];
#if RCT_DEBUG
if (!RCTValidateTypeOfViewCommandArgument(arg1, [NSNumber class], @"boolean", @"ScrollView", commandName, @"2nd")) {
return;
}
#endif
BOOL animated = [(NSNumber *)arg1 boolValue];
[componentView zoomToRect:rect animated:animated];
return;
}
}
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "ScrollEvent.h"
namespace facebook::react {
jsi::Value ScrollEvent::asJSIValue(jsi::Runtime& runtime) const {
auto payload = jsi::Object(runtime);
{
auto contentOffsetObj = jsi::Object(runtime);
contentOffsetObj.setProperty(runtime, "x", contentOffset.x);
contentOffsetObj.setProperty(runtime, "y", contentOffset.y);
payload.setProperty(runtime, "contentOffset", contentOffsetObj);
}
{
auto contentInsetObj = jsi::Object(runtime);
contentInsetObj.setProperty(runtime, "top", contentInset.top);
contentInsetObj.setProperty(runtime, "left", contentInset.left);
contentInsetObj.setProperty(runtime, "bottom", contentInset.bottom);
contentInsetObj.setProperty(runtime, "right", contentInset.right);
payload.setProperty(runtime, "contentInset", contentInsetObj);
}
{
auto contentSizeObj = jsi::Object(runtime);
contentSizeObj.setProperty(runtime, "width", contentSize.width);
contentSizeObj.setProperty(runtime, "height", contentSize.height);
payload.setProperty(runtime, "contentSize", contentSizeObj);
}
{
auto containerSizeObj = jsi::Object(runtime);
containerSizeObj.setProperty(runtime, "width", containerSize.width);
containerSizeObj.setProperty(runtime, "height", containerSize.height);
payload.setProperty(runtime, "layoutMeasurement", containerSizeObj);
}
payload.setProperty(runtime, "zoomScale", zoomScale);
payload.setProperty(runtime, "timestamp", timestamp * 1000);
return payload;
}
folly::dynamic ScrollEvent::asDynamic() const {
auto contentOffsetObj =
folly::dynamic::object("x", contentOffset.x)("y", contentOffset.y);
auto contentInsetObj = folly::dynamic::object("top", contentInset.top)(
"left", contentInset.left)("bottom", contentInset.bottom)(
"right", contentInset.right);
auto contentSizeObj = folly::dynamic::object("width", contentSize.width)(
"height", contentSize.height);
auto containerSizeObj = folly::dynamic::object("width", containerSize.width)(
"height", containerSize.height);
auto metrics =
folly::dynamic::object("contentOffset", std::move(contentOffsetObj))(
"contentInset", std::move(contentInsetObj))(
"contentSize", std::move(contentSizeObj))(
"layoutMeasurement", std::move(containerSizeObj))(
"zoomScale", zoomScale)("timestamp", timestamp * 1000);
return metrics;
};
std::optional<double> ScrollEvent::extractValue(
const std::vector<std::string>& path) const {
if (path.size() == 1 && path[0] == "zoomScale") {
return zoomScale;
} else if (path.size() == 2 && path[0] == "contentOffset") {
if (path[1] == "x") {
return contentOffset.x;
} else if (path[1] == "y") {
return contentOffset.y;
}
}
return EventPayload::extractValue(path);
}
EventPayloadType ScrollEvent::getType() const {
return EventPayloadType::ScrollEvent;
}
jsi::Value ScrollEndDragEvent::asJSIValue(jsi::Runtime& runtime) const {
auto payload = ScrollEvent::asJSIValue(runtime).asObject(runtime);
{
auto targetContentOffsetObj = jsi::Object(runtime);
targetContentOffsetObj.setProperty(runtime, "x", targetContentOffset.x);
targetContentOffsetObj.setProperty(runtime, "y", targetContentOffset.y);
payload.setProperty(runtime, "targetContentOffset", targetContentOffsetObj);
}
{
auto velocityObj = jsi::Object(runtime);
velocityObj.setProperty(runtime, "x", velocity.x);
velocityObj.setProperty(runtime, "y", velocity.y);
payload.setProperty(runtime, "velocity", velocityObj);
}
return payload;
}
folly::dynamic ScrollEndDragEvent::asDynamic() const {
auto metrics = ScrollEvent::asDynamic();
auto targetContentOffsetObj = folly::dynamic::object(
"x", targetContentOffset.x)("y", targetContentOffset.y);
metrics["targetContentOffset"] = std::move(targetContentOffsetObj);
auto velocityObj = folly::dynamic::object("x", velocity.x)("y", velocity.y);
metrics["velocity"] = std::move(velocityObj);
return metrics;
};
#if RN_DEBUG_STRING_CONVERTIBLE
std::string getDebugName(const ScrollEvent& /*scrollEvent*/) {
return "ScrollEvent";
}
std::vector<DebugStringConvertibleObject> getDebugProps(
const ScrollEvent& scrollEvent,
DebugStringConvertibleOptions options) {
return {
{"contentOffset",
getDebugDescription(scrollEvent.contentOffset, options)},
{"contentInset", getDebugDescription(scrollEvent.contentInset, options)},
{"contentSize", getDebugDescription(scrollEvent.contentSize, options)},
{"layoutMeasurement",
getDebugDescription(scrollEvent.containerSize, options)},
{"zoomScale", getDebugDescription(scrollEvent.zoomScale, options)},
{"timestamp", getDebugDescription(scrollEvent.timestamp, options)}};
}
#endif
} // namespace facebook::react

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <folly/dynamic.h>
#include <react/renderer/core/EventPayload.h>
#include <react/renderer/debug/DebugStringConvertible.h>
#include <react/renderer/graphics/RectangleEdges.h>
#include <react/renderer/graphics/Size.h>
namespace facebook::react {
struct ScrollEvent : public EventPayload {
Size contentSize;
Point contentOffset;
EdgeInsets contentInset;
Size containerSize;
Float zoomScale{};
/*
* The time in seconds when the touch occurred or when it was last mutated.
*/
Float timestamp{};
ScrollEvent() = default;
folly::dynamic asDynamic() const;
/*
* EventPayload implementations
*/
jsi::Value asJSIValue(jsi::Runtime &runtime) const override;
EventPayloadType getType() const override;
std::optional<double> extractValue(const std::vector<std::string> &path) const override;
};
struct ScrollEndDragEvent : public ScrollEvent {
Point targetContentOffset;
Point velocity;
ScrollEndDragEvent() = default;
ScrollEndDragEvent(const ScrollEvent &scrollEvent) : ScrollEvent(scrollEvent), targetContentOffset({}), velocity({})
{
}
folly::dynamic asDynamic() const;
/*
* EventPayload implementations
*/
jsi::Value asJSIValue(jsi::Runtime &runtime) const override;
};
#if RN_DEBUG_STRING_CONVERTIBLE
std::string getDebugName(const ScrollEvent &scrollEvent);
std::vector<DebugStringConvertibleObject> getDebugProps(
const ScrollEvent &scrollEvent,
DebugStringConvertibleOptions options);
#endif
} // namespace facebook::react

View File

@@ -0,0 +1,17 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/scrollview/ScrollViewShadowNode.h>
#include <react/renderer/core/ConcreteComponentDescriptor.h>
namespace facebook::react {
using ScrollViewComponentDescriptor = ConcreteComponentDescriptor<ScrollViewShadowNode>;
} // namespace facebook::react

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "ScrollViewEventEmitter.h"
namespace facebook::react {
void ScrollViewEventEmitter::onScroll(const ScrollEvent& scrollEvent) const {
dispatchUniqueEvent("scroll", std::make_shared<ScrollEvent>(scrollEvent));
}
void ScrollViewEventEmitter::onScrollToTop(
const ScrollEvent& scrollEvent) const {
dispatchUniqueEvent(
"scrollToTop", std::make_shared<ScrollEvent>(scrollEvent));
}
void ScrollViewEventEmitter::onScrollBeginDrag(
const ScrollEvent& scrollEvent) const {
dispatchScrollViewEvent("scrollBeginDrag", scrollEvent);
}
void ScrollViewEventEmitter::onScrollEndDrag(
const ScrollEndDragEvent& scrollEvent) const {
dispatchEvent(
"scrollEndDrag", std::make_shared<ScrollEndDragEvent>(scrollEvent));
}
void ScrollViewEventEmitter::onMomentumScrollBegin(
const ScrollEvent& scrollEvent) const {
dispatchScrollViewEvent("momentumScrollBegin", scrollEvent);
}
void ScrollViewEventEmitter::onMomentumScrollEnd(
const ScrollEvent& scrollEvent) const {
dispatchScrollViewEvent("momentumScrollEnd", scrollEvent);
}
void ScrollViewEventEmitter::dispatchScrollViewEvent(
std::string name,
const ScrollEvent& scrollEvent) const {
dispatchEvent(std::move(name), std::make_shared<ScrollEvent>(scrollEvent));
}
} // namespace facebook::react

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <memory>
#include <folly/dynamic.h>
#include <react/renderer/components/scrollview/ScrollEvent.h>
#include <react/renderer/components/view/ViewEventEmitter.h>
#include <react/renderer/core/EventEmitter.h>
namespace facebook::react {
class ScrollViewEventEmitter : public ViewEventEmitter {
public:
using ViewEventEmitter::ViewEventEmitter;
using Metrics = ScrollEvent;
using EndDragMetrics = ScrollEndDragEvent;
void onScroll(const ScrollEvent &scrollEvent) const;
void onScrollBeginDrag(const ScrollEvent &scrollEvent) const;
void onScrollEndDrag(const ScrollEndDragEvent &scrollEvent) const;
void onMomentumScrollBegin(const ScrollEvent &scrollEvent) const;
void onMomentumScrollEnd(const ScrollEvent &scrollEvent) const;
void onScrollToTop(const ScrollEvent &scrollEvent) const;
private:
void dispatchScrollViewEvent(std::string name, const ScrollEvent &scrollEvent) const;
};
} // namespace facebook::react

View File

@@ -0,0 +1,15 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/scrollview/HostPlatformScrollViewProps.h>
namespace facebook::react {
using ScrollViewProps = HostPlatformScrollViewProps;
using SharedScrollViewProps = std::shared_ptr<const ScrollViewProps>;
} // namespace facebook::react

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "ScrollViewShadowNode.h"
#include <react/debug/react_native_assert.h>
#include <react/renderer/core/LayoutMetrics.h>
namespace facebook::react {
// NOLINTNEXTLINE(facebook-hte-CArray)
const char ScrollViewComponentName[] = "ScrollView";
void ScrollViewShadowNode::updateStateIfNeeded() {
ensureUnsealed();
auto contentBoundingRect = Rect{};
for (const auto& childNode : getLayoutableChildNodes()) {
contentBoundingRect.unionInPlace(childNode->getLayoutMetrics().frame);
}
auto state = getStateData();
if (state.contentBoundingRect != contentBoundingRect) {
state.contentBoundingRect = contentBoundingRect;
setStateData(std::move(state));
}
}
void ScrollViewShadowNode::updateScrollContentOffsetIfNeeded() {
#ifndef ANDROID
if (getLayoutMetrics().layoutDirection == LayoutDirection::RightToLeft) {
// Yoga places `contentView` on the right side of `scrollView` when RTL
// layout is enforced. To correct for this, in RTL setting, correct the
// frame's origin. React Native Classic does this as well in
// `RCTScrollContentShadowView.m`.
for (auto layoutableNode : getLayoutableChildNodes()) {
auto layoutMetrics = layoutableNode->getLayoutMetrics();
if (layoutMetrics.frame.origin.x != 0) {
layoutMetrics.frame.origin.x = 0;
layoutableNode->setLayoutMetrics(layoutMetrics);
}
}
}
#endif
}
ScrollViewState ScrollViewShadowNode::initialStateData(
const Props::Shared& props,
const ShadowNodeFamily::Shared& /*family*/,
const ComponentDescriptor& /*componentDescriptor*/) {
return {static_cast<const ScrollViewProps&>(*props).contentOffset, {}, 0};
}
#pragma mark - LayoutableShadowNode
void ScrollViewShadowNode::layout(LayoutContext layoutContext) {
ConcreteViewShadowNode::layout(layoutContext);
updateScrollContentOffsetIfNeeded();
updateStateIfNeeded();
}
Point ScrollViewShadowNode::getContentOriginOffset(
bool includeTransform) const {
auto stateData = getStateData();
auto contentOffset = stateData.contentOffset;
auto transform = includeTransform ? getTransform() : Transform::Identity();
auto result = transform *
Vector{
.x = -contentOffset.x, .y = -contentOffset.y, .z = 0.0f, .w = 1.0f};
return {
.x = result.x,
.y = result.y + static_cast<float>(stateData.scrollAwayPaddingTop)};
}
} // namespace facebook::react

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/scrollview/ScrollViewEventEmitter.h>
#include <react/renderer/components/scrollview/ScrollViewProps.h>
#include <react/renderer/components/scrollview/ScrollViewState.h>
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
#include <react/renderer/core/LayoutContext.h>
#include <react/renderer/core/ShadowNodeFamily.h>
namespace facebook::react {
extern const char ScrollViewComponentName[];
/*
* `ShadowNode` for <ScrollView> component.
*/
class ScrollViewShadowNode final
: public ConcreteViewShadowNode<ScrollViewComponentName, ScrollViewProps, ScrollViewEventEmitter, ScrollViewState> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
static ScrollViewState initialStateData(
const Props::Shared &props,
const ShadowNodeFamily::Shared &family,
const ComponentDescriptor &componentDescriptor);
#pragma mark - LayoutableShadowNode
void layout(LayoutContext layoutContext) override;
Point getContentOriginOffset(bool includeTransform) const override;
private:
void updateStateIfNeeded();
void updateScrollContentOffsetIfNeeded();
};
} // namespace facebook::react

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "ScrollViewState.h"
namespace facebook::react {
ScrollViewState::ScrollViewState(
Point contentOffset,
Rect contentBoundingRect,
int scrollAwayPaddingTop)
: contentOffset(contentOffset),
contentBoundingRect(contentBoundingRect),
scrollAwayPaddingTop(scrollAwayPaddingTop) {}
Size ScrollViewState::getContentSize() const {
return contentBoundingRect.size;
}
} // namespace facebook::react

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/graphics/Float.h>
#include <react/renderer/graphics/Point.h>
#include <react/renderer/graphics/Rect.h>
#include <react/renderer/graphics/Size.h>
#ifdef RN_SERIALIZABLE_STATE
#include <folly/dynamic.h>
#endif
namespace facebook::react {
/*
* State for <ScrollView> component.
*/
class ScrollViewState final {
public:
ScrollViewState(Point contentOffset, Rect contentBoundingRect, int scrollAwayPaddingTop);
ScrollViewState() = default;
Point contentOffset;
Rect contentBoundingRect;
int scrollAwayPaddingTop;
/*
* View Culling has to be disabled when accessibility features are used.
* View Culling removes views from view hierarchy and for example VoiceOver
* wouldn't recognise there is a view outside of the viewport that it can
* scroll to.
*/
bool disableViewCulling{false};
/*
* Returns size of scrollable area.
*/
Size getContentSize() const;
#ifdef RN_SERIALIZABLE_STATE
ScrollViewState(const ScrollViewState &previousState, folly::dynamic data)
: contentOffset({(Float)data["contentOffsetLeft"].getDouble(), (Float)data["contentOffsetTop"].getDouble()}),
contentBoundingRect({}),
scrollAwayPaddingTop((Float)data["scrollAwayPaddingTop"].getDouble()) {};
folly::dynamic getDynamic() const
{
return folly::dynamic::object("contentOffsetLeft", contentOffset.x)("contentOffsetTop", contentOffset.y)(
"scrollAwayPaddingTop", scrollAwayPaddingTop);
};
#endif
};
} // namespace facebook::react

View File

@@ -0,0 +1,174 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <folly/dynamic.h>
#include <react/renderer/components/scrollview/primitives.h>
#include <react/renderer/core/PropsParserContext.h>
#include <react/renderer/core/propsConversions.h>
#include <unordered_map>
namespace facebook::react {
inline void fromRawValue(const PropsParserContext &context, const RawValue &value, ScrollViewSnapToAlignment &result)
{
auto string = (std::string)value;
if (string == "start") {
result = ScrollViewSnapToAlignment::Start;
return;
}
if (string == "center") {
result = ScrollViewSnapToAlignment::Center;
return;
}
if (string == "end") {
result = ScrollViewSnapToAlignment::End;
return;
}
abort();
}
inline void fromRawValue(const PropsParserContext &context, const RawValue &value, ScrollViewIndicatorStyle &result)
{
auto string = (std::string)value;
if (string == "default") {
result = ScrollViewIndicatorStyle::Default;
return;
}
if (string == "black") {
result = ScrollViewIndicatorStyle::Black;
return;
}
if (string == "white") {
result = ScrollViewIndicatorStyle::White;
return;
}
abort();
}
inline void
fromRawValue(const PropsParserContext &context, const RawValue &value, ScrollViewKeyboardDismissMode &result)
{
auto string = (std::string)value;
if (string == "none") {
result = ScrollViewKeyboardDismissMode::None;
return;
}
if (string == "on-drag") {
result = ScrollViewKeyboardDismissMode::OnDrag;
return;
}
if (string == "interactive") {
result = ScrollViewKeyboardDismissMode::Interactive;
return;
}
abort();
}
inline void
fromRawValue(const PropsParserContext &context, const RawValue &value, ContentInsetAdjustmentBehavior &result)
{
auto string = (std::string)value;
if (string == "never") {
result = ContentInsetAdjustmentBehavior::Never;
return;
}
if (string == "automatic") {
result = ContentInsetAdjustmentBehavior::Automatic;
return;
}
if (string == "scrollableAxes") {
result = ContentInsetAdjustmentBehavior::ScrollableAxes;
return;
}
if (string == "always") {
result = ContentInsetAdjustmentBehavior::Always;
return;
}
abort();
}
inline void
fromRawValue(const PropsParserContext &context, const RawValue &value, ScrollViewMaintainVisibleContentPosition &result)
{
auto map = (std::unordered_map<std::string, RawValue>)value;
auto minIndexForVisible = map.find("minIndexForVisible");
if (minIndexForVisible != map.end()) {
fromRawValue(context, minIndexForVisible->second, result.minIndexForVisible);
}
auto autoscrollToTopThreshold = map.find("autoscrollToTopThreshold");
if (autoscrollToTopThreshold != map.end()) {
fromRawValue(context, autoscrollToTopThreshold->second, result.autoscrollToTopThreshold);
}
}
inline std::string toString(const ScrollViewSnapToAlignment &value)
{
switch (value) {
case ScrollViewSnapToAlignment::Start:
return "start";
case ScrollViewSnapToAlignment::Center:
return "center";
case ScrollViewSnapToAlignment::End:
return "end";
}
}
#if RN_DEBUG_STRING_CONVERTIBLE
inline std::string toString(const ScrollViewIndicatorStyle &value)
{
switch (value) {
case ScrollViewIndicatorStyle::Default:
return "default";
case ScrollViewIndicatorStyle::Black:
return "black";
case ScrollViewIndicatorStyle::White:
return "white";
}
}
inline std::string toString(const ScrollViewKeyboardDismissMode &value)
{
switch (value) {
case ScrollViewKeyboardDismissMode::None:
return "none";
case ScrollViewKeyboardDismissMode::OnDrag:
return "on-drag";
case ScrollViewKeyboardDismissMode::Interactive:
return "interactive";
}
}
inline std::string toString(const ContentInsetAdjustmentBehavior &value)
{
switch (value) {
case ContentInsetAdjustmentBehavior::Never:
return "never";
case ContentInsetAdjustmentBehavior::Automatic:
return "automatic";
case ContentInsetAdjustmentBehavior::ScrollableAxes:
return "scrollableAxes";
case ContentInsetAdjustmentBehavior::Always:
return "always";
}
}
inline std::string toString(const std::optional<ScrollViewMaintainVisibleContentPosition> &value)
{
if (!value) {
return "null";
}
return "{minIndexForVisible: " + toString(value.value().minIndexForVisible) +
", autoscrollToTopThreshold: " + toString(value.value().autoscrollToTopThreshold) + "}";
}
#endif
} // namespace facebook::react

View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/scrollview/AndroidHorizontalScrollContentViewShadowNode.h>
#include <react/renderer/core/ConcreteComponentDescriptor.h>
namespace facebook::react {
using AndroidHorizontalScrollContentViewComponentDescriptor =
ConcreteComponentDescriptor<AndroidHorizontalScrollContentViewShadowNode>;
} // namespace facebook::react

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <react/renderer/components/scrollview/AndroidHorizontalScrollContentViewShadowNode.h>
namespace facebook::react {
const char AndroidHorizontalScrollContentViewShadowNodeComponentName[] =
"AndroidHorizontalScrollContentView";
void AndroidHorizontalScrollContentViewShadowNode::layout(
LayoutContext layoutContext) {
ConcreteViewShadowNode::layout(layoutContext);
// When the layout direction is RTL, we expect Yoga to give us a layout
// that extends off the screen to the left so we re-center it to be at most
// zero (where the scrolling offset will be adjusted to match if larger than
// parent width on the Android component side).
if (layoutMetrics_.layoutDirection == LayoutDirection::RightToLeft &&
layoutMetrics_.frame.origin.x < 0) {
layoutMetrics_.frame.origin.x = 0;
}
}
} // namespace facebook::react

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/scrollview/ScrollViewEventEmitter.h>
#include <react/renderer/components/scrollview/ScrollViewState.h>
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
#include <react/renderer/core/LayoutContext.h>
namespace facebook::react {
extern const char AndroidHorizontalScrollContentViewShadowNodeComponentName[];
class AndroidHorizontalScrollContentViewShadowNode final
: public ConcreteViewShadowNode<
AndroidHorizontalScrollContentViewShadowNodeComponentName,
ViewProps,
ScrollViewEventEmitter,
ScrollViewState> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
void layout(LayoutContext layoutContext) override;
};
} // namespace facebook::react

View File

@@ -0,0 +1,402 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "HostPlatformScrollViewProps.h"
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/renderer/components/scrollview/conversions.h>
#include <react/renderer/core/graphicsConversions.h>
#include <react/renderer/debug/debugStringConvertibleUtils.h>
#include <react/renderer/core/propsConversions.h>
namespace facebook::react {
HostPlatformScrollViewProps::HostPlatformScrollViewProps(
const PropsParserContext& context,
const HostPlatformScrollViewProps& sourceProps,
const RawProps& rawProps)
: BaseScrollViewProps(context, sourceProps, rawProps),
sendMomentumEvents(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.sendMomentumEvents
: convertRawProp(
context,
rawProps,
"sendMomentumEvents",
sourceProps.sendMomentumEvents,
true)),
nestedScrollEnabled(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.nestedScrollEnabled
: convertRawProp(
context,
rawProps,
"nestedScrollEnabled",
sourceProps.nestedScrollEnabled,
true)),
fadingEdgeLength(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.fadingEdgeLength
: convertRawProp(
context,
rawProps,
"fadingEdgeLength",
sourceProps.fadingEdgeLength,
nullptr)),
overScrollMode(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.overScrollMode
: convertRawProp(
context,
rawProps,
"overScrollMode",
sourceProps.overScrollMode,
"auto")),
endFillColor(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.endFillColor
: convertRawProp(
context,
rawProps,
"endFillColor",
sourceProps.endFillColor,
clearColor())) {}
void HostPlatformScrollViewProps::setProp(
const PropsParserContext& context,
RawPropsPropNameHash hash,
const char* propName,
const RawValue& value) {
// All Props structs setProp methods must always, unconditionally,
// call all super::setProp methods, since multiple structs may
// reuse the same values.
BaseScrollViewProps::setProp(context, hash, propName, value);
static auto defaults = HostPlatformScrollViewProps{};
switch (hash) {
RAW_SET_PROP_SWITCH_CASE_BASIC(sendMomentumEvents);
RAW_SET_PROP_SWITCH_CASE_BASIC(nestedScrollEnabled);
RAW_SET_PROP_SWITCH_CASE_BASIC(fadingEdgeLength);
RAW_SET_PROP_SWITCH_CASE_BASIC(overScrollMode);
RAW_SET_PROP_SWITCH_CASE_BASIC(endFillColor);
}
}
#pragma mark - DebugStringConvertible
#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList HostPlatformScrollViewProps::getDebugProps()
const {
auto defaultScrollViewProps = HostPlatformScrollViewProps{};
return BaseScrollViewProps::getDebugProps() +
SharedDebugStringConvertibleList{
debugStringConvertibleItem(
"sendMomentumEvents",
sendMomentumEvents,
defaultScrollViewProps.sendMomentumEvents),
debugStringConvertibleItem(
"nestedScrollEnabled",
nestedScrollEnabled,
defaultScrollViewProps.nestedScrollEnabled),
debugStringConvertibleItem(
"overScrollMode",
overScrollMode,
defaultScrollViewProps.overScrollMode),
debugStringConvertibleItem(
"endFillColor",
endFillColor,
defaultScrollViewProps.endFillColor)};
}
#endif
static folly::dynamic convertScrollViewMaintainVisibleContentPosition(
const ScrollViewMaintainVisibleContentPosition& value) {
folly::dynamic result = folly::dynamic::object();
result["minIndexForVisible"] = value.minIndexForVisible;
if (value.autoscrollToTopThreshold.has_value()) {
result["autoscrollToTopThreshold"] = value.autoscrollToTopThreshold.value();
}
return result;
}
static folly::dynamic convertEdgeInsets(const EdgeInsets& edgeInsets) {
folly::dynamic edgeInsetsResult = folly::dynamic::object();
edgeInsetsResult["left"] = edgeInsets.left;
edgeInsetsResult["top"] = edgeInsets.top;
edgeInsetsResult["right"] = edgeInsets.right;
edgeInsetsResult["bottom"] = edgeInsets.bottom;
return edgeInsetsResult;
}
static folly::dynamic convertPoint(const Point& point) {
folly::dynamic pointResult = folly::dynamic::object();
pointResult["y"] = point.y;
pointResult["x"] = point.x;
return pointResult;
}
ComponentName HostPlatformScrollViewProps::getDiffPropsImplementationTarget()
const {
return "ScrollView";
}
folly::dynamic HostPlatformScrollViewProps::getDiffProps(
const Props* prevProps) const {
static const auto defaultProps = HostPlatformScrollViewProps();
const HostPlatformScrollViewProps* oldProps = prevProps == nullptr
? &defaultProps
: static_cast<const HostPlatformScrollViewProps*>(prevProps);
folly::dynamic result = ViewProps::getDiffProps(oldProps);
if (alwaysBounceHorizontal != oldProps->alwaysBounceHorizontal) {
result["alwaysBounceHorizontal"] = alwaysBounceHorizontal;
}
if (alwaysBounceVertical != oldProps->alwaysBounceVertical) {
result["alwaysBounceVertical"] = alwaysBounceVertical;
}
if (bounces != oldProps->bounces) {
result["bounces"] = bounces;
}
if (bouncesZoom != oldProps->bouncesZoom) {
result["bouncesZoom"] = bouncesZoom;
}
if (canCancelContentTouches != oldProps->canCancelContentTouches) {
result["canCancelContentTouches"] = canCancelContentTouches;
}
if (centerContent != oldProps->centerContent) {
result["centerContent"] = centerContent;
}
if (automaticallyAdjustContentInsets !=
oldProps->automaticallyAdjustContentInsets) {
result["automaticallyAdjustContentInsets"] =
automaticallyAdjustContentInsets;
}
if (automaticallyAdjustsScrollIndicatorInsets !=
oldProps->automaticallyAdjustsScrollIndicatorInsets) {
result["automaticallyAdjustsScrollIndicatorInsets"] =
automaticallyAdjustsScrollIndicatorInsets;
}
if (automaticallyAdjustKeyboardInsets !=
oldProps->automaticallyAdjustKeyboardInsets) {
result["automaticallyAdjustKeyboardInsets"] =
automaticallyAdjustKeyboardInsets;
}
if (decelerationRate != oldProps->decelerationRate) {
result["decelerationRate"] = decelerationRate;
}
if (endDraggingSensitivityMultiplier !=
oldProps->endDraggingSensitivityMultiplier) {
result["endDraggingSensitivityMultiplier"] =
endDraggingSensitivityMultiplier;
}
if (directionalLockEnabled != oldProps->directionalLockEnabled) {
result["directionalLockEnabled"] = directionalLockEnabled;
}
if (indicatorStyle != oldProps->indicatorStyle) {
switch (indicatorStyle) {
case ScrollViewIndicatorStyle::Default:
result["indicatorStyle"] = "default";
break;
case ScrollViewIndicatorStyle::Black:
result["indicatorStyle"] = "black";
break;
case ScrollViewIndicatorStyle::White:
result["indicatorStyle"] = "white";
break;
}
}
if (keyboardDismissMode != oldProps->keyboardDismissMode) {
switch (keyboardDismissMode) {
case ScrollViewKeyboardDismissMode::None:
result["keyboardDismissMode"] = "none";
break;
case ScrollViewKeyboardDismissMode::OnDrag:
result["keyboardDismissMode"] = "on-drag";
break;
case ScrollViewKeyboardDismissMode::Interactive:
result["keyboardDismissMode"] = "interactive";
break;
}
}
if (maintainVisibleContentPosition !=
oldProps->maintainVisibleContentPosition) {
if (maintainVisibleContentPosition.has_value()) {
result["maintainVisibleContentPosition"] =
convertScrollViewMaintainVisibleContentPosition(
maintainVisibleContentPosition.value());
} else {
result["maintainVisibleContentPosition"] = folly::dynamic(nullptr);
}
}
if (maximumZoomScale != oldProps->maximumZoomScale) {
result["maximumZoomScale"] = maximumZoomScale;
}
if (minimumZoomScale != oldProps->minimumZoomScale) {
result["minimumZoomScale"] = minimumZoomScale;
}
if (scrollEnabled != oldProps->scrollEnabled) {
result["scrollEnabled"] = scrollEnabled;
}
if (pagingEnabled != oldProps->pagingEnabled) {
result["pagingEnabled"] = pagingEnabled;
}
if (pinchGestureEnabled != oldProps->pinchGestureEnabled) {
result["pinchGestureEnabled"] = pinchGestureEnabled;
}
if (scrollsToTop != oldProps->scrollsToTop) {
result["scrollsToTop"] = scrollsToTop;
}
if (showsHorizontalScrollIndicator !=
oldProps->showsHorizontalScrollIndicator) {
result["showsHorizontalScrollIndicator"] = showsHorizontalScrollIndicator;
}
if (showsVerticalScrollIndicator != oldProps->showsVerticalScrollIndicator) {
result["showsVerticalScrollIndicator"] = showsVerticalScrollIndicator;
}
if (persistentScrollbar != oldProps->persistentScrollbar) {
result["persistentScrollbar"] = persistentScrollbar;
}
if (horizontal != oldProps->horizontal) {
result["horizontal"] = horizontal;
}
if (scrollEventThrottle != oldProps->scrollEventThrottle) {
result["scrollEventThrottle"] = scrollEventThrottle;
}
if (zoomScale != oldProps->zoomScale) {
result["zoomScale"] = zoomScale;
}
if (contentInset != oldProps->contentInset) {
result["contentInset"] = convertEdgeInsets(contentInset);
}
if (contentOffset != oldProps->contentOffset) {
result["contentOffset"] = convertPoint(contentOffset);
}
if (scrollIndicatorInsets != oldProps->scrollIndicatorInsets) {
result["scrollIndicatorInsets"] = convertEdgeInsets(scrollIndicatorInsets);
}
if (snapToInterval != oldProps->snapToInterval) {
result["snapToInterval"] = snapToInterval;
}
if (snapToAlignment != oldProps->snapToAlignment) {
switch (snapToAlignment) {
case ScrollViewSnapToAlignment::Start:
result["snapToAlignment"] = "start";
break;
case ScrollViewSnapToAlignment::Center:
result["snapToAlignment"] = "center";
break;
case ScrollViewSnapToAlignment::End:
result["snapToAlignment"] = "end";
break;
}
}
if (disableIntervalMomentum != oldProps->disableIntervalMomentum) {
result["disableIntervalMomentum"] = disableIntervalMomentum;
}
if (snapToOffsets != oldProps->snapToOffsets) {
auto snapToOffsetsArray = folly::dynamic::array();
for (const auto& snapToOffset : snapToOffsets) {
snapToOffsetsArray.push_back(snapToOffset);
}
result["snapToOffsets"] = snapToOffsetsArray;
}
if (snapToStart != oldProps->snapToStart) {
result["snapToStart"] = snapToStart;
}
if (snapToEnd != oldProps->snapToEnd) {
result["snapToEnd"] = snapToEnd;
}
if (contentInsetAdjustmentBehavior !=
oldProps->contentInsetAdjustmentBehavior) {
switch (contentInsetAdjustmentBehavior) {
case ContentInsetAdjustmentBehavior::Never:
result["contentInsetAdjustmentBehavior"] = "never";
break;
case ContentInsetAdjustmentBehavior::Automatic:
result["contentInsetAdjustmentBehavior"] = "automatic";
break;
case ContentInsetAdjustmentBehavior::ScrollableAxes:
result["contentInsetAdjustmentBehavior"] = "scrollableAxes";
break;
case ContentInsetAdjustmentBehavior::Always:
result["contentInsetAdjustmentBehavior"] = "always";
break;
}
}
if (scrollToOverflowEnabled != oldProps->scrollToOverflowEnabled) {
result["scrollToOverflowEnabled"] = scrollToOverflowEnabled;
}
if (isInvertedVirtualizedList != oldProps->isInvertedVirtualizedList) {
result["isInvertedVirtualizedList"] = isInvertedVirtualizedList;
}
if (sendMomentumEvents != oldProps->sendMomentumEvents) {
result["sendMomentumEvents"] = sendMomentumEvents;
}
if (nestedScrollEnabled != oldProps->nestedScrollEnabled) {
result["nestedScrollEnabled"] = nestedScrollEnabled;
}
if (fadingEdgeLength != oldProps->fadingEdgeLength) {
result["fadingEdgeLength"] = fadingEdgeLength;
}
if (overScrollMode != oldProps->overScrollMode) {
result["overScrollMode"] = overScrollMode;
}
if (endFillColor != oldProps->endFillColor) {
result["endFillColor"] = *endFillColor;
}
return result;
}
} // namespace facebook::react

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/scrollview/BaseScrollViewProps.h>
#include <react/renderer/components/scrollview/primitives.h>
#include <react/renderer/components/view/ViewProps.h>
#include <react/renderer/core/PropsParserContext.h>
namespace facebook::react {
class HostPlatformScrollViewProps : public BaseScrollViewProps {
public:
HostPlatformScrollViewProps() = default;
HostPlatformScrollViewProps(
const PropsParserContext &context,
const HostPlatformScrollViewProps &sourceProps,
const RawProps &rawProps);
void
setProp(const PropsParserContext &context, RawPropsPropNameHash hash, const char *propName, const RawValue &value);
#pragma mark - Props
bool sendMomentumEvents{};
bool nestedScrollEnabled{};
folly::dynamic fadingEdgeLength{};
std::string overScrollMode{"auto"};
SharedColor endFillColor{clearColor()};
#pragma mark - DebugStringConvertible
#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList getDebugProps() const override;
#endif
ComponentName getDiffPropsImplementationTarget() const override;
folly::dynamic getDiffProps(const Props *prevProps) const override;
};
} // namespace facebook::react

View File

@@ -0,0 +1,14 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/components/scrollview/BaseScrollViewProps.h>
namespace facebook::react {
using HostPlatformScrollViewProps = BaseScrollViewProps;
} // namespace facebook::react

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <optional>
#include <tuple>
namespace facebook::react {
enum class ScrollViewSnapToAlignment { Start, Center, End };
enum class ScrollViewIndicatorStyle { Default, Black, White };
enum class ScrollViewKeyboardDismissMode { None, OnDrag, Interactive };
enum class ContentInsetAdjustmentBehavior { Never, Automatic, ScrollableAxes, Always };
class ScrollViewMaintainVisibleContentPosition final {
public:
int minIndexForVisible{0};
std::optional<int> autoscrollToTopThreshold{};
bool operator==(const ScrollViewMaintainVisibleContentPosition &rhs) const
{
return std::tie(this->minIndexForVisible, this->autoscrollToTopThreshold) ==
std::tie(rhs.minIndexForVisible, rhs.autoscrollToTopThreshold);
}
bool operator!=(const ScrollViewMaintainVisibleContentPosition &rhs) const
{
return !(*this == rhs);
}
};
} // namespace facebook::react

View File

@@ -0,0 +1,14 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <memory>
#include <gtest/gtest.h>
TEST(ScrollViewTest, testSomething) {
// TODO
}