From f9519a2634adf9b6f2857b0118ae7d19b52a1673 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Fri, 18 Oct 2019 08:16:38 -0600 Subject: [PATCH] wip -- memoizing --- example/App.tsx | 41 +- example/ios/example.xcodeproj/project.pbxproj | 333 +------------ .../xcshareddata/xcschemes/example.xcscheme | 22 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../AppIcon.appiconset/Contents.json | 15 + example/src/shared-components.tsx | 9 +- src/index.tsx | 2 +- src/pager-2.tsx | 457 ++++++++++++++++++ src/util.ts | 2 +- 9 files changed, 538 insertions(+), 351 deletions(-) create mode 100644 example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/pager-2.tsx diff --git a/example/App.tsx b/example/App.tsx index 15f4c73..f2610a2 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -9,7 +9,7 @@ console.disableYellowBox = true; import React, {useState} from 'react'; -import {SafeAreaView, View} from 'react-native'; +import {SafeAreaView, View, Text} from 'react-native'; import {InlineCards} from './src/inline-cards'; import {KilterCards} from './src/kilter-cards'; @@ -18,24 +18,49 @@ import {SwipeCards} from './src/swipe-cards'; import {Stack} from './src/stack'; import {Tabs} from './src/tabs'; import {MyPager} from './src/basic-example'; -import {PagerProvider} from '@crowdlinker/react-native-pager'; +import {Pager} from '@crowdlinker/react-native-pager'; import {ContainerStyle} from './src/panhandler-width'; +import {Slide} from './src/shared-components'; + +const stackConfig: any = { + transform: [ + { + scale: { + inputRange: [-1, 0, 1], + outputRange: [0.95, 1, 0.95], + }, + }, + ], + + zIndex: offset => offset, +}; const App = () => { const [activeIndex, setActiveIndex] = useState(1); function onChange(nextIndex: number) { - // console.log({nextIndex}); + console.log({nextIndex}); setActiveIndex(nextIndex); } return ( - - - - + + + + + + + + + + + {`Active index: ${activeIndex}`} ); diff --git a/example/ios/example.xcodeproj/project.pbxproj b/example/ios/example.xcodeproj/project.pbxproj index 1edbff0..59bbc39 100644 --- a/example/ios/example.xcodeproj/project.pbxproj +++ b/example/ios/example.xcodeproj/project.pbxproj @@ -8,16 +8,10 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; }; - 11D260E457736DAC92D89439 /* libPods-example-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CFF809717AA2CEDF7155800D /* libPods-example-tvOSTests.a */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; - 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; - 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 2DCD954D1E0B4F2C00145EB5 /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; }; - 8725D952B3862126F48D0E2E /* libPods-example-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B42AF3230FA0C8448D27AF9 /* libPods-example-tvOS.a */; }; 875DAE3FC0AAC0DDCEFCEE76 /* libPods-exampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DE004CFC5D7C94AAA1D4CC8 /* libPods-exampleTests.a */; }; E50328FBA66D51ABC9044376 /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 734CE017E4D11139A39F475B /* libPods-example.a */; }; /* End PBXBuildFile section */ @@ -30,13 +24,6 @@ remoteGlobalIDString = 13B07F861A680F5B00A75B9A; remoteInfo = example; }; - 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7; - remoteInfo = "example-tvOS"; - }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -51,8 +38,6 @@ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = example/main.m; sourceTree = ""; }; - 2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "example-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 466F3A040231D85B4B4ED00F /* Pods-example-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOS.release.xcconfig"; path = "Target Support Files/Pods-example-tvOS/Pods-example-tvOS.release.xcconfig"; sourceTree = ""; }; 532B1EF3A55127953EA1FE8A /* Pods-example-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-example-tvOSTests/Pods-example-tvOSTests.debug.xcconfig"; sourceTree = ""; }; 5B42AF3230FA0C8448D27AF9 /* libPods-example-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -86,22 +71,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 2D02E4781E0B4A5D006451C7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 8725D952B3862126F48D0E2E /* libPods-example-tvOS.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 2D02E48D1E0B4A5D006451C7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 11D260E457736DAC92D89439 /* libPods-example-tvOSTests.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -161,7 +130,6 @@ 708FBAF9C6D205F0633E216C /* Pods-exampleTests.debug.xcconfig */, F7F8A42F3ABC22EE717273AA /* Pods-exampleTests.release.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -192,8 +160,6 @@ children = ( 13B07F961A680F5B00A75B9A /* example.app */, 00E356EE1AD99517003FC87E /* exampleTests.xctest */, - 2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */, - 2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */, ); name = Products; sourceTree = ""; @@ -240,45 +206,6 @@ productReference = 13B07F961A680F5B00A75B9A /* example.app */; productType = "com.apple.product-type.application"; }; - 2D02E47A1E0B4A5D006451C7 /* example-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOS" */; - buildPhases = ( - 3FB0AAD2B54C9CEDE8307673 /* [CP] Check Pods Manifest.lock */, - FD10A7F122414F3F0027D42C /* Start Packager */, - 2D02E4771E0B4A5D006451C7 /* Sources */, - 2D02E4781E0B4A5D006451C7 /* Frameworks */, - 2D02E4791E0B4A5D006451C7 /* Resources */, - 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "example-tvOS"; - productName = "example-tvOS"; - productReference = 2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */; - productType = "com.apple.product-type.application"; - }; - 2D02E48F1E0B4A5D006451C7 /* example-tvOSTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOSTests" */; - buildPhases = ( - CFF59ED859E523D41F4E04F0 /* [CP] Check Pods Manifest.lock */, - 2D02E48C1E0B4A5D006451C7 /* Sources */, - 2D02E48D1E0B4A5D006451C7 /* Frameworks */, - 2D02E48E1E0B4A5D006451C7 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */, - ); - name = "example-tvOSTests"; - productName = "example-tvOSTests"; - productReference = 2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -290,16 +217,11 @@ TargetAttributes = { 00E356ED1AD99517003FC87E = { CreatedOnToolsVersion = 6.2; + DevelopmentTeam = 7DK33WZYS5; TestTargetID = 13B07F861A680F5B00A75B9A; }; - 2D02E47A1E0B4A5D006451C7 = { - CreatedOnToolsVersion = 8.2.1; - ProvisioningStyle = Automatic; - }; - 2D02E48F1E0B4A5D006451C7 = { - CreatedOnToolsVersion = 8.2.1; - ProvisioningStyle = Automatic; - TestTargetID = 2D02E47A1E0B4A5D006451C7; + 13B07F861A680F5B00A75B9A = { + DevelopmentTeam = 7DK33WZYS5; }; }; }; @@ -308,6 +230,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -318,8 +241,6 @@ targets = ( 13B07F861A680F5B00A75B9A /* example */, 00E356ED1AD99517003FC87E /* exampleTests */, - 2D02E47A1E0B4A5D006451C7 /* example-tvOS */, - 2D02E48F1E0B4A5D006451C7 /* example-tvOSTests */, ); }; /* End PBXProject section */ @@ -341,21 +262,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 2D02E4791E0B4A5D006451C7 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 2D02E48E1E0B4A5D006451C7 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -373,42 +279,6 @@ shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; }; - 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Bundle React Native Code And Images"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; - }; - 3FB0AAD2B54C9CEDE8307673 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-example-tvOS-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; 702BE342796AE0FF5F6E1960 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -453,28 +323,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - CFF59ED859E523D41F4E04F0 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-example-tvOSTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; FD10A7F022414F080027D42C /* Start Packager */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -494,25 +342,6 @@ shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; showEnvVarsInLog = 0; }; - FD10A7F122414F3F0027D42C /* Start Packager */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Start Packager"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -533,23 +362,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 2D02E4771E0B4A5D006451C7 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */, - 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 2D02E48C1E0B4A5D006451C7 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2DCD954D1E0B4F2C00145EB5 /* exampleTests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -558,11 +370,6 @@ target = 13B07F861A680F5B00A75B9A /* example */; targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; }; - 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 2D02E47A1E0B4A5D006451C7 /* example-tvOS */; - targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -583,6 +390,7 @@ baseConfigurationReference = 708FBAF9C6D205F0633E216C /* Pods-exampleTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = 7DK33WZYS5; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", @@ -607,6 +415,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; + DEVELOPMENT_TEAM = 7DK33WZYS5; INFOPLIST_FILE = exampleTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -628,6 +437,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; + DEVELOPMENT_TEAM = 7DK33WZYS5; INFOPLIST_FILE = example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( @@ -647,6 +457,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 7DK33WZYS5; INFOPLIST_FILE = example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( @@ -660,116 +471,6 @@ }; name = Release; }; - 2D02E4971E0B4A5E006451C7 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = AAF21A135CF25EFDDFA72D03 /* Pods-example-tvOS.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "example-tvOS/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 2D02E4981E0B4A5E006451C7 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 466F3A040231D85B4B4ED00F /* Pods-example-tvOS.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "example-tvOS/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; - 2D02E4991E0B4A5E006451C7 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 532B1EF3A55127953EA1FE8A /* Pods-example-tvOSTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "example-tvOSTests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS"; - TVOS_DEPLOYMENT_TARGET = 10.1; - }; - name = Debug; - }; - 2D02E49A1E0B4A5E006451C7 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = F1C1D9BBC06AAE84000246C0 /* Pods-example-tvOSTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "example-tvOSTests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS"; - TVOS_DEPLOYMENT_TARGET = 10.1; - }; - name = Release; - }; 83CBBA201A601CBA00E9B192 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -890,24 +591,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D02E4971E0B4A5E006451C7 /* Debug */, - 2D02E4981E0B4A5E006451C7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOSTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D02E4991E0B4A5E006451C7 /* Debug */, - 2D02E49A1E0B4A5E006451C7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme index 1cef262..7ad0109 100644 --- a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme +++ b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme @@ -55,6 +55,15 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -67,17 +76,6 @@ - - - - - - - - + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json b/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json index 48e64ae..d25ce24 100644 --- a/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,5 +1,15 @@ { "images": [ + { + "idiom": "iphone", + "size": "20x20", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "20x20", + "scale": "3x" + }, { "idiom": "iphone", "size": "29x29", @@ -29,6 +39,11 @@ "idiom": "iphone", "size": "60x60", "scale": "3x" + }, + { + "idiom": "ios-marketing", + "size": "1024x1024", + "scale": "1x" } ], "info": { diff --git a/example/src/shared-components.tsx b/example/src/shared-components.tsx index 4f668a2..d32126f 100644 --- a/example/src/shared-components.tsx +++ b/example/src/shared-components.tsx @@ -16,6 +16,7 @@ import { useInterpolation, } from '@crowdlinker/react-native-pager'; import Animated from 'react-native-reanimated'; +import {ReText} from 'react-native-redash'; const colors = [ 'aquamarine', @@ -28,10 +29,10 @@ const colors = [ 'salmon', ]; -function Slide() { +function Slide({index}: any) { // const [count, setCount] = useState(0); - const focused = useFocus(); - const index = useIndex(); + // const focused = useFocus(); + // const index = useIndex(); // const style = useInterpolation({ // transform: [ // { @@ -51,9 +52,11 @@ function Slide() { alignItems: 'center', borderRadius: 10, marginHorizontal: 5, + borderWidth: 1, backgroundColor: colors[index % colors.length], }}> {`Screen: ${index}`} + {/* */} {/* {`Focused: ${focused}`} */} {/* {`Count: ${count}`} diff --git a/src/index.tsx b/src/index.tsx index 3a36690..a4bb9ca 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,3 +1,3 @@ -export * from './pager'; +export * from './pager-2'; export * from './pagination'; export { interpolateWithConfig } from './util'; diff --git a/src/pager-2.tsx b/src/pager-2.tsx new file mode 100644 index 0000000..b6ff012 --- /dev/null +++ b/src/pager-2.tsx @@ -0,0 +1,457 @@ +import React, { + useState, + Children, + createContext, + useContext, + useEffect, + memo, + cloneElement, + useMemo, +} from 'react'; +import { StyleSheet, LayoutChangeEvent, ViewStyle } from 'react-native'; +import Animated from 'react-native-reanimated'; +import { + PanGestureHandler, + State, + PanGestureHandlerProperties, +} from 'react-native-gesture-handler'; +import { memoize, interpolateWithConfig, runSpring } from './util'; + +export type SpringConfig = { + damping: Animated.Adaptable; + mass: Animated.Adaptable; + stiffness: Animated.Adaptable; + overshootClamping: Animated.Adaptable | boolean; + restSpeedThreshold: Animated.Adaptable; + restDisplacementThreshold: Animated.Adaptable; + toValue: Animated.Adaptable; +}; + +// copied from react-native-reanimated for now, can't get the export +export enum Extrapolate { + EXTEND = 'extend', + CLAMP = 'clamp', + IDENTITY = 'identity', +} + +interface InterpolationConfig { + inputRange: ReadonlyArray>; + outputRange: ReadonlyArray>; + extrapolate?: Extrapolate; + extrapolateLeft?: Extrapolate; + extrapolateRight?: Extrapolate; +} + +type iInterpolationFn = ( + offset: Animated.Node +) => Animated.Node; + +interface iInterpolationConfig extends InterpolationConfig { + unit?: string; +} + +type iTransformProp = { + [transformProp: string]: iInterpolationConfig | iInterpolationFn; +}; + +export interface iPageInterpolation { + [animatedProp: string]: + | iTransformProp[] + | iInterpolationConfig + | iInterpolationFn; +} + +const VERTICAL = 1; +const HORIZONTAL = 2; + +const { + event, + block, + Value, + divide, + cond, + eq, + add, + or, + stopClock, + Clock, + set, + clockRunning, + spring, + startClock, + multiply, + neq, + sub, + call, + max, + min, + greaterThan, + abs, + lessThan, + ceil, + proc, + // @ts-ignore + debug, +} = Animated; + +export interface iPager { + activeIndex?: number; + onChange?: (nextIndex: number) => void; + initialIndex?: number; + children: React.ReactNode[]; + springConfig?: Partial; + pageInterpolation?: iPageInterpolation; + panProps?: Partial; + pageSize?: number; + threshold?: number; + minIndex?: number; + maxIndex?: number; + adjacentChildOffset?: number; + style?: ViewStyle; + containerStyle?: ViewStyle; + animatedValue?: Animated.Value; + animatedIndex?: Animated.Value; + type?: 'horizontal' | 'vertical'; + clamp?: { + prev?: number; + next?: number; + }; + clampDrag?: { + prev?: number; + next?: number; + }; +} +const REALLY_BIG_NUMBER = 1000000000; + +const minMax = proc((value, minimum, maximum) => + min(max(value, minimum), maximum) +); + +function Pager({ + children, + panProps, + style, + type = 'horizontal', + containerStyle, + adjacentChildOffset, + activeIndex: parentActiveIndex, + onChange: parentOnChange, + initialIndex, + threshold = 0.1, + springConfig, + clampDrag = { + next: REALLY_BIG_NUMBER, + prev: REALLY_BIG_NUMBER, + }, + clamp = { + next: REALLY_BIG_NUMBER, + prev: REALLY_BIG_NUMBER, + }, + + pageInterpolation, +}: iPager) { + const isControlled = parentActiveIndex !== undefined; + + const [_activeIndex, _onChange] = useState(initialIndex); + + const activeIndex = isControlled + ? (parentActiveIndex as number) + : (_activeIndex as number); + + const onChange = isControlled ? (parentOnChange as any) : (_onChange as any); + + const dragX = memoize(new Value(0)); + const dragY = memoize(new Value(0)); + const gestureState = memoize(new Value(0)); + + const handleGesture = memoize( + event( + [ + { + nativeEvent: { + translationX: dragX, + translationY: dragY, + }, + }, + ], + { useNativeDriver: true } + ) + ); + + const handleStateChange = memoize( + event( + [ + { + nativeEvent: { + state: gestureState, + }, + }, + ], + { + useNativeDriver: true, + } + ) + ); + + const numberOfScreens = Children.count(children); + const [width, setWidth] = useState(-1); + const [height, setHeight] = useState(-1); + + const dimension = memoize(new Value(0)); + const targetDimension = type === 'vertical' ? 'height' : 'width'; + const targetTransform = type === 'vertical' ? 'translateY' : 'translateX'; + const delta = type === 'vertical' ? dragY : dragX; + const totalDimension = multiply(dimension, numberOfScreens); + + function handleLayout({ nativeEvent: { layout } }: LayoutChangeEvent) { + layout.width !== width && setWidth(layout.width); + layout.height !== height && setHeight(layout.height); + } + + const TYPE = type === 'vertical' ? VERTICAL : HORIZONTAL; + + Animated.useCode( + cond( + // dimension already set to last layout + or(eq(dimension, width), eq(dimension, height)), + [], + [cond(eq(TYPE, VERTICAL), set(dimension, height), set(dimension, width))] + ), + [width, height] + ); + + const dragStart = memoize(new Value(0)); + const swiping = memoize(new Value(0)); + const position = memoize(new Value(activeIndex)); + const nextIndex = memoize(new Value(activeIndex)); + const change = memoize(new Value(0)); + const absChange = memoize(new Value(0)); + const indexChange = memoize(new Value(0)); + const clamped = memoize(new Value(0)); + const clock = memoize(new Clock()); + const shouldTransition = memoize(new Value(0)); + + // props that might change over time should be reactive: + const animatedThreshold = useAnimatedValue(threshold); + const animatedActiveIndex = useAnimatedValue(activeIndex); + const clampDragPrev = useAnimatedValue(clampDrag.prev, REALLY_BIG_NUMBER); + const clampDragNext = useAnimatedValue(clampDrag.next, REALLY_BIG_NUMBER); + + useEffect(() => { + nextIndex.setValue(activeIndex); + }, [activeIndex]); + + const animatedIndex = memoize( + block([ + cond( + eq(gestureState, State.ACTIVE), + [ + cond(clockRunning(clock), stopClock(clock)), + cond(swiping, 0, [set(dragStart, position), set(swiping, 1)]), + + set(change, sub(animatedActiveIndex, position)), + set(absChange, abs(change)), + set(shouldTransition, greaterThan(absChange, animatedThreshold)), + + set( + clamped, + minMax( + divide(delta, dimension), + multiply(clampDragNext, -1), + clampDragPrev + ) + ), + + debug('clamped', clamped), + debug('clampDragNext', clampDragNext), + debug('clampDragPrev', clampDragPrev), + debug('change', divide(delta, dimension)), + + set(position, sub(dragStart, clamped)), + ], + [ + cond(swiping, [ + set(swiping, 0), + set(nextIndex, animatedActiveIndex), + cond(shouldTransition, [ + set(indexChange, ceil(absChange)), + set( + nextIndex, + cond( + greaterThan(change, 0), + sub(animatedActiveIndex, indexChange), + add(animatedActiveIndex, indexChange) + ) + ), + call([nextIndex], ([nextIndex]) => onChange(nextIndex)), + ]), + ]), + + set(position, runSpring(clock, position, nextIndex, springConfig)), + ] + ), + position, + ]) + ); + + const clampPrevValue = useAnimatedValue(clamp.prev, numberOfScreens); + const clampNextValue = useAnimatedValue(clamp.next, numberOfScreens); + + const minimum = memoize( + multiply(sub(animatedIndex, clampPrevValue), dimension) + ); + + const maximum = memoize( + multiply(add(animatedIndex, clampNextValue), dimension) + ); + + const containerTranslation = memoize(multiply(animatedIndex, dimension, -1)); + + const adjacentChildren = + adjacentChildOffset !== undefined + ? children.slice( + Math.max(activeIndex - adjacentChildOffset, 0), + Math.min(activeIndex + adjacentChildOffset + 1, numberOfScreens) + ) + : children; + + const defaultContainerStyle = + style && style.height ? { height: style.height } : undefined; + + return ( + + + + + + + {width === -1 + ? null + : adjacentChildren.map((child: any, i) => { + // use map instead of React.Children because we want to track + // the keys of these children by there index + // React.Children shifts these key values intelligently, but it + // causes issues with the memoized values in components + let index = i; + + if (adjacentChildOffset !== undefined) { + index = + activeIndex <= adjacentChildOffset + ? i + : activeIndex - adjacentChildOffset + i; + } + + return ( + + {child} + + ); + })} + + + + + + + ); +} + +function Page({ + children, + index, + minimum, + maximum, + dimension, + targetTransform, + targetDimension, + pageInterpolation, + animatedIndex, +}: any) { + const position = memoize(multiply(index, dimension)); + const translation = memoize(minMax(position, minimum, maximum)); + + const defaultStyle = memoize({ + // map to height / width value depending on vertical / horizontal configuration + [targetDimension]: dimension, + // min-max the position based on clamp values + // this means the will have a container that is always positioned + // in the same place, but the inner view can be translated within these bounds + transform: [ + { + [targetTransform]: translation, + }, + ], + }); + + const offset = memoize(sub(index, animatedIndex)); + + // apply interpolation configs to + const interpolatedStyles = memoize( + interpolateWithConfig(offset, pageInterpolation) + ); + + // take out zIndex here as it needs to be applied to siblings, which inner containers + // are not, however the outer container requires the absolute translateX/Y to properly + // position itself + let { zIndex, ...otherStyles } = interpolatedStyles; + + // zIndex is not a requirement of interpolation + // it will be clear when someone needs it as views will overlap with some configurations + if (!zIndex) { + zIndex = 0; + } + + return ( + + + {children} + + + ); +} + +function useAnimatedValue( + value?: number, + defaultValue?: number +): Animated.Value { + const initialValue = value || defaultValue || 0; + const animatedValue = memoize(new Value(initialValue)); + + useEffect(() => { + if (value !== undefined) { + animatedValue.setValue(value); + } + }, [value]); + + return animatedValue; +} + +export { Pager }; diff --git a/src/util.ts b/src/util.ts index 8af9676..bcfa9e3 100644 --- a/src/util.ts +++ b/src/util.ts @@ -111,7 +111,7 @@ function runSpring( ] ), spring(clock, state, config), - cond(state.finished, [stopClock(clock), set(position, state.position)]), + cond(state.finished, [stopClock(clock), set(state.position, position)]), state.position, ]); }