├── .watchmanconfig ├── .gitattributes ├── app.json ├── .eslintrc.js ├── babel.config.js ├── android ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── ic_launcher_round.png │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── samplemaps │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ └── AndroidManifest.xml │ │ └── debug │ │ │ └── AndroidManifest.xml │ ├── debug.keystore │ ├── proguard-rules.pro │ ├── build_defs.bzl │ ├── BUCK │ └── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle ├── gradle.properties ├── build.gradle ├── gradlew.bat └── gradlew ├── ios ├── samplemaps │ ├── Images.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Sample │ │ ├── Resources │ │ │ ├── Assets.xcassets │ │ │ │ ├── Contents.json │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ │ ├── Icon-App-57x57@1x.png │ │ │ │ │ ├── Icon-App-57x57@2x.png │ │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ │ ├── Icon-App-72x72@1x.png │ │ │ │ │ ├── Icon-App-72x72@2x.png │ │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ │ ├── ItunesArtwork@2x.png │ │ │ │ │ ├── Icon-Small-50x50@1x.png │ │ │ │ │ ├── Icon-Small-50x50@2x.png │ │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ │ └── Contents.json │ │ │ │ └── LaunchImage.launchimage │ │ │ │ │ ├── iPhone4_LaunchScreen_Placeholder.png │ │ │ │ │ ├── iPhone5_LaunchScreen_Placeholder.png │ │ │ │ │ ├── iPhone6_LaunchScreen_Placeholder.png │ │ │ │ │ ├── iPhoneX_LaunchScreen_Placeholder.png │ │ │ │ │ ├── iPhone6Plus_LaunchScreen_Placeholder.png │ │ │ │ │ └── Contents.json │ │ │ ├── Preview.png │ │ │ ├── Fonts │ │ │ │ ├── Lato-Bold.ttf │ │ │ │ └── Lato-Regular.ttf │ │ │ └── Info.plist │ │ ├── View Controllers │ │ │ ├── User Groups │ │ │ │ ├── Presentables │ │ │ │ │ ├── UserGroupHeaderPresentable.swift │ │ │ │ │ └── UserGroupMemberPresentable.swift │ │ │ │ ├── Views │ │ │ │ │ ├── UserGroupHeaderView.swift │ │ │ │ │ └── UserGroupMemberCell.swift │ │ │ │ └── UserGroupViewController.swift │ │ │ ├── User Groups (Stacked) │ │ │ │ ├── UserGroupStackedViewController.swift │ │ │ │ └── StackedProfileViewController.swift │ │ │ ├── Basic │ │ │ │ └── BasicViewController.swift │ │ │ ├── Alert (Transient) │ │ │ │ └── TransientAlertViewController.swift │ │ │ ├── Alert │ │ │ │ ├── AlertViewController.swift │ │ │ │ └── AlertView.swift │ │ │ ├── Full Screen │ │ │ │ └── FullScreenNavController.swift │ │ │ └── User Groups (Navigation Controller) │ │ │ │ ├── NavigationController.swift │ │ │ │ └── ProfileViewController.swift │ │ ├── AppDelegate.swift │ │ └── SampleViewController.swift │ ├── AppDelegate.h │ ├── main.m │ ├── PanModal │ │ ├── PanModal.h │ │ ├── Info2.plist │ │ ├── Presenter │ │ │ ├── PanModalPresenter.swift │ │ │ └── UIViewController+PanModalPresenter.swift │ │ ├── View │ │ │ ├── PanContainerView.swift │ │ │ └── DimmedView.swift │ │ ├── Presentable │ │ │ ├── PanModalHeight.swift │ │ │ ├── PanModalPresentable+UIViewController.swift │ │ │ ├── PanModalPresentable+Defaults.swift │ │ │ ├── PanModalPresentable+LayoutHelpers.swift │ │ │ └── PanModalPresentable.swift │ │ ├── Animator │ │ │ ├── PanModalAnimator.swift │ │ │ └── PanModalPresentationAnimator.swift │ │ └── Delegate │ │ │ └── PanModalPresentationDelegate.swift │ ├── Info.plist │ ├── AppDelegate.m │ └── Base.lproj │ │ └── LaunchScreen.xib ├── samplemaps-Bridging-Header.h ├── File.swift ├── SAmpl │ └── Fileee.swift ├── samplemaps.xcworkspace │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── contents.xcworkspacedata ├── samplemapsTests │ ├── Info.plist │ └── samplemapsTests.m ├── samplemaps-tvOSTests │ └── Info.plist ├── samplemaps-tvOS │ └── Info.plist ├── Podfile ├── PanModule.m ├── samplemaps.xcodeproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── samplemaps.xcscheme │ │ └── samplemaps-tvOS.xcscheme └── Podfile.lock ├── .buckconfig ├── .prettierrc.js ├── Modal.js ├── README.md ├── index.js ├── __tests__ └── App-test.js ├── metro.config.js ├── package.json ├── .gitignore ├── .flowconfig └── App.js /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samplemaps", 3 | "displayName": "samplemaps" 4 | } -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; 5 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | samplemaps 3 | 4 | -------------------------------------------------------------------------------- /android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/debug.keystore -------------------------------------------------------------------------------- /ios/samplemaps/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /ios/samplemaps-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; 7 | -------------------------------------------------------------------------------- /Modal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {requireNativeComponent} from "react-native"; 3 | 4 | export default requireNativeComponent('ModalView'); 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Preview.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Fonts/Lato-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Fonts/Lato-Bold.ttf -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Fonts/Lato-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Fonts/Lato-Regular.ttf -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # slack-pan-sheet-react-native-experiment 2 | 3 | work in progress. Will be dope. stay tuned. 4 | 5 | 6 | it's me talking about it: https://twitter.com/mosdnk/status/1233097798251425795 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /ios/File.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // samplemaps 4 | // 5 | // Created by Michał Osadnik on 14/01/2020. 6 | // Copyright © 2020 Facebook. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import {AppRegistry} from 'react-native'; 6 | import App from './App'; 7 | import {name as appName} from './app.json'; 8 | AppRegistry.registerComponent(appName, () => App); 9 | -------------------------------------------------------------------------------- /ios/SAmpl/Fileee.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Fileee.swift 3 | // samplemaps 4 | // 5 | // Created by Michał Osadnik on 14/01/2020. 6 | // Copyright © 2020 Facebook. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'samplemaps' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhone4_LaunchScreen_Placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhone4_LaunchScreen_Placeholder.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhone5_LaunchScreen_Placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhone5_LaunchScreen_Placeholder.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhone6_LaunchScreen_Placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhone6_LaunchScreen_Placeholder.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhoneX_LaunchScreen_Placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhoneX_LaunchScreen_Placeholder.png -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhone6Plus_LaunchScreen_Placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osdnk/slack-pan-sheet-react-native-experiment/HEAD/ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/iPhone6Plus_LaunchScreen_Placeholder.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ios/samplemaps.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /__tests__/App-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../App'; 8 | 9 | // Note: test renderer must be required after react-native. 10 | import renderer from 'react-test-renderer'; 11 | 12 | it('renders correctly', () => { 13 | renderer.create(); 14 | }); 15 | -------------------------------------------------------------------------------- /metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | module.exports = { 9 | transformer: { 10 | getTransformOptions: async () => ({ 11 | transform: { 12 | experimentalImportSupport: false, 13 | inlineRequires: false, 14 | }, 15 | }), 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /ios/samplemaps.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 9 | 10 | 11 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/User Groups/Presentables/UserGroupHeaderPresentable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserGroupHeaderPresentable.swift 3 | // PanModal 4 | // 5 | // Created by Tosin Afolabi on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct UserGroupHeaderPresentable: Equatable { 12 | 13 | let handle: String 14 | let description: String 15 | let memberCount: Int 16 | 17 | } 18 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/samplemaps/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.samplemaps; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. This is used to schedule 9 | * rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "samplemaps"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/User Groups/Presentables/UserGroupMemberPresentable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserGroupMemberPresentable.swift 3 | // PanModal 4 | // 5 | // Created by Tosin Afolabi on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct UserGroupMemberPresentable: Equatable { 12 | 13 | let name: String 14 | let role: String 15 | let avatarBackgroundColor: UIColor 16 | 17 | } 18 | -------------------------------------------------------------------------------- /ios/samplemaps/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (nonatomic, strong) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ios/samplemaps/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/PanModal.h: -------------------------------------------------------------------------------- 1 | // 2 | // PanModal.h 3 | // PanModal 4 | // 5 | // Created by Tosin A on 3/13/19. 6 | // Copyright © 2019 Detail. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for PanModal. 12 | FOUNDATION_EXPORT double PanModalVersionNumber; 13 | 14 | //! Project version string for PanModal. 15 | FOUNDATION_EXPORT const unsigned char PanModalVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // PanModal 4 | // 5 | // Created by Stephen Sowole on 10/9/18. 6 | // Copyright © 2018 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | //@UIApplicationMain 12 | class AppDelegate2: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | window = UIWindow(frame: UIScreen.main.bounds) 18 | // window?.rootViewController = UINavigationController(rootViewController: SampleViewController()) 19 | window?.makeKeyAndVisible() 20 | return true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Info2.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/User Groups (Stacked)/UserGroupStackedViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserGroupStackedViewController.swift 3 | // PanModal 4 | // 5 | // Created by Stephen Sowole on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class UserGroupStackedViewController: UserGroupViewController { 12 | 13 | // override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 14 | // tableView.deselectRow(at: indexPath, animated: true) 15 | // 16 | // let presentable = members[indexPath.row] 17 | // let viewController = StackedProfileViewController(presentable: presentable) 18 | // 19 | // presentPanModal() 20 | // } 21 | 22 | override var shortFormHeight: PanModalHeight { 23 | return longFormHeight 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ios/samplemapsTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samplemaps", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "test": "jest", 10 | "lint": "eslint ." 11 | }, 12 | "dependencies": { 13 | "react": "16.9.0", 14 | "react-native": "0.61.5" 15 | }, 16 | "devDependencies": { 17 | "@babel/core": "^7.8.3", 18 | "@babel/runtime": "^7.8.3", 19 | "@react-native-community/eslint-config": "^0.0.6", 20 | "@react-native-community/eslint-plugin": "^1.0.0", 21 | "babel-jest": "^24.9.0", 22 | "eslint": "^6.8.0", 23 | "jest": "^24.9.0", 24 | "metro-react-native-babel-preset": "^0.56.4", 25 | "react-test-renderer": "16.9.0" 26 | }, 27 | "jest": { 28 | "preset": "react-native" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ios/samplemaps-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/Basic/BasicViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BasicViewController.swift 3 | // PanModal 4 | // 5 | // Created by Stephen Sowole on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BasicViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | view.backgroundColor = #colorLiteral(red: 0.1019607843, green: 0.1137254902, blue: 0.1294117647, alpha: 1) 16 | } 17 | } 18 | 19 | extension BasicViewController: PanModalPresentable { 20 | 21 | override var preferredStatusBarStyle: UIStatusBarStyle { 22 | return .lightContent 23 | } 24 | 25 | var panScrollable: UIScrollView? { 26 | return nil 27 | } 28 | 29 | var longFormHeight: PanModalHeight { 30 | return .maxHeightWithTopInset(200) 31 | } 32 | 33 | var anchorModalToLongForm: Bool { 34 | return false 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useAndroidX=true 21 | android.enableJetifier=true 22 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Presenter/PanModalPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanModalPresenter.swift 3 | // PanModal 4 | // 5 | // Copyright © 2019 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | A protocol for objects that will present a view controller as a PanModal 13 | 14 | - Usage: 15 | ``` 16 | viewController.presentPanModal(viewControllerToPresent: presentingVC, 17 | sourceView: presentingVC.view, 18 | sourceRect: .zero) 19 | ``` 20 | */ 21 | protocol PanModalPresenter2: AnyObject { 22 | 23 | /** 24 | A flag that returns true if the current presented view controller 25 | is using the PanModalPresentationDelegate 26 | */ 27 | var isPanModalPresented: Bool { get } 28 | 29 | /** 30 | Presents a view controller that conforms to the PanModalPresentable protocol 31 | */ 32 | func presentPanModal(view: UIView) 33 | 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | yarn-error.log 37 | 38 | # BUCK 39 | buck-out/ 40 | \.buckd/ 41 | *.keystore 42 | !debug.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | 58 | # CocoaPods 59 | /ios/Pods/ 60 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/samplemaps/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "28.0.3" 6 | minSdkVersion = 16 7 | compileSdkVersion = 28 8 | targetSdkVersion = 28 9 | } 10 | repositories { 11 | google() 12 | jcenter() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle:3.4.2") 16 | 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | } 21 | 22 | allprojects { 23 | repositories { 24 | mavenLocal() 25 | maven { 26 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 27 | url("$rootDir/../node_modules/react-native/android") 28 | } 29 | maven { 30 | // Android JSC is installed from npm 31 | url("$rootDir/../node_modules/jsc-android/dist") 32 | } 33 | 34 | google() 35 | jcenter() 36 | maven { url 'https://jitpack.io' } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/View/PanContainerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanContainerView.swift 3 | // PanModal 4 | // 5 | // Copyright © 2018 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | A view wrapper around the presented view in a PanModal transition. 13 | 14 | This allows us to make modifications to the presented view without 15 | having to do those changes directly on the view 16 | */ 17 | class PanContainerView: UIView { 18 | 19 | init(presentedView: UIView, frame: CGRect) { 20 | super.init(frame: frame) 21 | addSubview(presentedView) 22 | } 23 | 24 | @available(*, unavailable) 25 | required init?(coder aDecoder: NSCoder) { 26 | fatalError("init(coder:) has not been implemented") 27 | } 28 | 29 | } 30 | 31 | extension UIView { 32 | 33 | /** 34 | Convenience property for retrieving a PanContainerView instance 35 | from the view hierachy 36 | */ 37 | var panContainerView: PanContainerView? { 38 | return subviews.first(where: { view -> Bool in 39 | view is PanContainerView 40 | }) as? PanContainerView 41 | } 42 | 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Presentable/PanModalHeight.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanModalHeight.swift 3 | // PanModal 4 | // 5 | // Copyright © 2019 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | An enum that defines the possible states of the height of a pan modal container view 13 | for a given presentation state (shortForm, longForm) 14 | */ 15 | public enum PanModalHeight: Equatable { 16 | 17 | /** 18 | Sets the height to be the maximum height (+ topOffset) 19 | */ 20 | case maxHeight 21 | 22 | /** 23 | Sets the height to be the max height with a specified top inset. 24 | - Note: A value of 0 is equivalent to .maxHeight 25 | */ 26 | case maxHeightWithTopInset(CGFloat) 27 | 28 | /** 29 | Sets the height to be the specified content height 30 | */ 31 | case contentHeight(CGFloat) 32 | 33 | /** 34 | Sets the height to be the specified content height 35 | & also ignores the bottomSafeAreaInset 36 | */ 37 | case contentHeightIgnoringSafeArea(CGFloat) 38 | 39 | /** 40 | Sets the height to be the intrinsic content height 41 | */ 42 | case intrinsicHeight 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Animator/PanModalAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanModalAnimator.swift 3 | // PanModal 4 | // 5 | // Copyright © 2019 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | Helper animation function to keep animations consistent. 13 | */ 14 | struct PanModalAnimator { 15 | 16 | /** 17 | Constant Animation Properties 18 | */ 19 | struct Constants { 20 | static let defaultTransitionDuration: TimeInterval = 0.5 21 | } 22 | 23 | static func animate(_ animations: @escaping PanModalPresentable2.AnimationBlockType, 24 | config: PanModalPresentable2?, 25 | _ completion: PanModalPresentable2.AnimationCompletionType? = nil) { 26 | 27 | let transitionDuration = config?.transitionDuration ?? Constants.defaultTransitionDuration 28 | let springDamping = config?.springDamping ?? 1.0 29 | let animationOptions = config?.transitionAnimationOptions ?? [] 30 | 31 | UIView.animate(withDuration: transitionDuration, 32 | delay: 0, 33 | usingSpringWithDamping: springDamping, 34 | initialSpringVelocity: 0, 35 | options: animationOptions, 36 | animations: animations, 37 | completion: completion) 38 | } 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") 12 | 13 | lib_deps = [] 14 | 15 | create_aar_targets(glob(["libs/*.aar"])) 16 | 17 | create_jar_targets(glob(["libs/*.jar"])) 18 | 19 | android_library( 20 | name = "all-libs", 21 | exported_deps = lib_deps, 22 | ) 23 | 24 | android_library( 25 | name = "app-code", 26 | srcs = glob([ 27 | "src/main/java/**/*.java", 28 | ]), 29 | deps = [ 30 | ":all-libs", 31 | ":build_config", 32 | ":res", 33 | ], 34 | ) 35 | 36 | android_build_config( 37 | name = "build_config", 38 | package = "com.samplemaps", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.samplemaps", 44 | res = "src/main/res", 45 | ) 46 | 47 | android_binary( 48 | name = "app", 49 | keystore = "//android/keystores:debug", 50 | manifest = "src/main/AndroidManifest.xml", 51 | package_type = "debug", 52 | deps = [ 53 | ":app-code", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIAppFonts 24 | 25 | Lato-Regular.ttf 26 | Lato-Bold.ttf 27 | 28 | UIRequiredDeviceCapabilities 29 | 30 | armv7 31 | 32 | UIRequiresFullScreen 33 | 34 | UISupportedInterfaceOrientations 35 | 36 | UIInterfaceOrientationPortrait 37 | 38 | UISupportedInterfaceOrientations~ipad 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationPortraitUpsideDown 42 | UIInterfaceOrientationLandscapeLeft 43 | UIInterfaceOrientationLandscapeRight 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "2436h", 7 | "filename" : "iPhoneX_LaunchScreen_Placeholder.png", 8 | "minimum-system-version" : "11.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "736h", 16 | "filename" : "iPhone6Plus_LaunchScreen_Placeholder.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "portrait", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "extent" : "full-screen", 23 | "idiom" : "iphone", 24 | "subtype" : "667h", 25 | "filename" : "iPhone6_LaunchScreen_Placeholder.png", 26 | "minimum-system-version" : "8.0", 27 | "orientation" : "portrait", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "orientation" : "portrait", 32 | "idiom" : "iphone", 33 | "filename" : "iPhone4_LaunchScreen_Placeholder.png", 34 | "extent" : "full-screen", 35 | "minimum-system-version" : "7.0", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "extent" : "full-screen", 40 | "idiom" : "iphone", 41 | "subtype" : "retina4", 42 | "filename" : "iPhone5_LaunchScreen_Placeholder.png", 43 | "minimum-system-version" : "7.0", 44 | "orientation" : "portrait", 45 | "scale" : "2x" 46 | } 47 | ], 48 | "info" : { 49 | "version" : 1, 50 | "author" : "xcode" 51 | } 52 | } -------------------------------------------------------------------------------- /ios/samplemaps-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSExceptionDomains 28 | 29 | localhost 30 | 31 | NSExceptionAllowsInsecureHTTPLoads 32 | 33 | 34 | 35 | 36 | NSLocationWhenInUseUsageDescription 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /ios/samplemaps/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | samplemaps 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSExceptionDomains 32 | 33 | localhost 34 | 35 | NSExceptionAllowsInsecureHTTPLoads 36 | 37 | 38 | 39 | 40 | NSLocationWhenInUseUsageDescription 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UIViewControllerBasedStatusBarAppearance 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /ios/samplemaps/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import "AppDelegate.h" 9 | 10 | #import 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import "samplemaps-Swift.h" 16 | 17 | #import 18 | 19 | #import 20 | 21 | #import 22 | 23 | 24 | 25 | 26 | @implementation AppDelegate 27 | 28 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 29 | { 30 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 31 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge 32 | moduleName:@"samplemaps" 33 | initialProperties:nil]; 34 | 35 | 36 | 37 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 38 | 39 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 40 | UIViewController *rootViewController = [[UIViewController alloc] init]; 41 | rootViewController.view = rootView; 42 | self.window.rootViewController = rootViewController; 43 | [self.window makeKeyAndVisible]; 44 | return YES; 45 | } 46 | 47 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 48 | { 49 | #if DEBUG 50 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 51 | #else 52 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 53 | #endif 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/View/DimmedView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DimmedView.swift 3 | // PanModal 4 | // 5 | // Copyright © 2017 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | A dim view for use as an overlay over content you want dimmed. 13 | */ 14 | public class DimmedView: UIView { 15 | 16 | /** 17 | Represents the possible states of the dimmed view. 18 | max, off or a percentage of dimAlpha. 19 | */ 20 | enum DimState { 21 | case max 22 | case off 23 | case percent(CGFloat) 24 | } 25 | 26 | // MARK: - Properties 27 | 28 | /** 29 | The state of the dimmed view 30 | */ 31 | var dimState: DimState = .off { 32 | didSet { 33 | switch dimState { 34 | case .max: 35 | alpha = 1.0 36 | case .off: 37 | alpha = 0.0 38 | case .percent(let percentage): 39 | alpha = max(0.0, min(1.0, percentage)) 40 | } 41 | } 42 | } 43 | 44 | /** 45 | The closure to be executed when a tap occurs 46 | */ 47 | var didTap: ((_ recognizer: UIGestureRecognizer) -> Void)? 48 | 49 | /** 50 | Tap gesture recognizer 51 | */ 52 | private lazy var tapGesture: UIGestureRecognizer = { 53 | return UITapGestureRecognizer(target: self, action: #selector(didTapView)) 54 | }() 55 | 56 | // MARK: - Initializers 57 | 58 | init(dimColor: UIColor = UIColor.black.withAlphaComponent(0.7)) { 59 | super.init(frame: .zero) 60 | alpha = 0.0 61 | backgroundColor = dimColor 62 | addGestureRecognizer(tapGesture) 63 | } 64 | 65 | required public init?(coder aDecoder: NSCoder) { 66 | fatalError() 67 | } 68 | 69 | // MARK: - Event Handlers 70 | 71 | @objc private func didTapView() { 72 | didTap?(tapGesture) 73 | } 74 | 75 | } 76 | #endif 77 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/Alert (Transient)/TransientAlertViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransientAlertViewController.swift 3 | // PanModal 4 | // 5 | // Created by Stephen Sowole on 3/1/19. 6 | // Copyright © 2019 Detail. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TransientAlertViewController: AlertViewController { 12 | 13 | private weak var timer: Timer? 14 | private var countdown: Int = 5 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | alertView.titleLabel.text = "Transient Alert" 19 | updateMessage() 20 | } 21 | 22 | override func viewDidAppear(_ animated: Bool) { 23 | super.viewDidAppear(animated) 24 | startTimer() 25 | } 26 | 27 | private func startTimer() { 28 | timer?.invalidate() 29 | if #available(iOS 10.0, *) { 30 | timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in 31 | self?.countdown -= 1 32 | self?.updateMessage() 33 | } 34 | } else { 35 | // Fallback on earlier versions 36 | } 37 | } 38 | 39 | @objc func updateMessage() { 40 | guard countdown > 0 else { 41 | invalidateTimer() 42 | dismiss(animated: true, completion: nil) 43 | return 44 | } 45 | alertView.message.text = "Message disppears in \(countdown) seconds" 46 | } 47 | 48 | func invalidateTimer() { 49 | timer?.invalidate() 50 | } 51 | 52 | deinit { 53 | invalidateTimer() 54 | } 55 | 56 | // MARK: - Pan Modal Presentable 57 | 58 | override var showDragIndicator: Bool { 59 | return false 60 | } 61 | 62 | override var anchorModalToLongForm: Bool { 63 | return true 64 | } 65 | 66 | override var panModalBackgroundColor: UIColor { 67 | return .clear 68 | } 69 | 70 | override var isUserInteractionEnabled: Bool { 71 | return false 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/Alert/AlertViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlertViewController.swift 3 | // PanModal 4 | // 5 | // Created by Stephen Sowole on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class AlertViewController: UIViewController, PanModalPresentable { 12 | 13 | private let alertViewHeight: CGFloat = 68 14 | 15 | let alertView: AlertView = { 16 | let alertView = AlertView() 17 | alertView.layer.cornerRadius = 10 18 | return alertView 19 | }() 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | setupView() 24 | } 25 | 26 | private func setupView() { 27 | view.addSubview(alertView) 28 | alertView.translatesAutoresizingMaskIntoConstraints = false 29 | alertView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true 30 | alertView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true 31 | alertView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true 32 | alertView.heightAnchor.constraint(equalToConstant: alertViewHeight).isActive = true 33 | } 34 | 35 | // MARK: - PanModalPresentable 36 | 37 | var panScrollable: UIScrollView? { 38 | return nil 39 | } 40 | 41 | var shortFormHeight: PanModalHeight { 42 | return .contentHeight(alertViewHeight) 43 | } 44 | 45 | var longFormHeight: PanModalHeight { 46 | return shortFormHeight 47 | } 48 | 49 | var panModalBackgroundColor: UIColor { 50 | return UIColor.black.withAlphaComponent(0.1) 51 | } 52 | 53 | var shouldRoundTopCorners: Bool { 54 | return false 55 | } 56 | 57 | var showDragIndicator: Bool { 58 | return true 59 | } 60 | 61 | var anchorModalToLongForm: Bool { 62 | return false 63 | } 64 | 65 | var isUserInteractionEnabled: Bool { 66 | return true 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/Full Screen/FullScreenNavController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FullScreenNavController.swift 3 | // PanModalDemo 4 | // 5 | // Created by Stephen Sowole on 5/2/19. 6 | // Copyright © 2019 Detail. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class FullScreenNavController: UINavigationController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | pushViewController(FullScreenViewController(), animated: false) 16 | } 17 | } 18 | 19 | extension FullScreenNavController: PanModalPresentable { 20 | 21 | var panScrollable: UIScrollView? { 22 | return nil 23 | } 24 | 25 | var topOffset: CGFloat { 26 | return 0.0 27 | } 28 | 29 | var springDamping: CGFloat { 30 | return 1.0 31 | } 32 | 33 | var transitionDuration: Double { 34 | return 0.4 35 | } 36 | 37 | var transitionAnimationOptions: UIView.AnimationOptions { 38 | return [.allowUserInteraction, .beginFromCurrentState] 39 | } 40 | 41 | var shouldRoundTopCorners: Bool { 42 | return false 43 | } 44 | 45 | var showDragIndicator: Bool { 46 | return false 47 | } 48 | } 49 | 50 | private class FullScreenViewController: UIViewController { 51 | 52 | let textLabel: UILabel = { 53 | let label = UILabel() 54 | label.text = "Drag downwards to dismiss" 55 | label.font = UIFont(name: "Lato-Bold", size: 17) 56 | label.translatesAutoresizingMaskIntoConstraints = false 57 | return label 58 | }() 59 | 60 | override func viewDidLoad() { 61 | super.viewDidLoad() 62 | title = "Full Screen" 63 | view.backgroundColor = .white 64 | setupConstraints() 65 | } 66 | 67 | private func setupConstraints() { 68 | view.addSubview(textLabel) 69 | textLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 70 | textLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /ios/samplemapsTests/samplemapsTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | #import 12 | #import 13 | 14 | #define TIMEOUT_SECONDS 600 15 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 16 | 17 | @interface samplemapsTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation samplemapsTests 22 | 23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 24 | { 25 | if (test(view)) { 26 | return YES; 27 | } 28 | for (UIView *subview in [view subviews]) { 29 | if ([self findSubviewInView:subview matching:test]) { 30 | return YES; 31 | } 32 | } 33 | return NO; 34 | } 35 | 36 | - (void)testRendersWelcomeScreen 37 | { 38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 40 | BOOL foundElement = NO; 41 | 42 | __block NSString *redboxError = nil; 43 | #ifdef DEBUG 44 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 45 | if (level >= RCTLogLevelError) { 46 | redboxError = message; 47 | } 48 | }); 49 | #endif 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | #ifdef DEBUG 64 | RCTSetLogFunction(RCTDefaultLogFunction); 65 | #endif 66 | 67 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 68 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 69 | } 70 | 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore polyfills 9 | node_modules/react-native/Libraries/polyfills/.* 10 | 11 | ; These should not be required directly 12 | ; require from fbjs/lib instead: require('fbjs/lib/warning') 13 | node_modules/warning/.* 14 | 15 | ; Flow doesn't support platforms 16 | .*/Libraries/Utilities/LoadingView.js 17 | 18 | [untyped] 19 | .*/node_modules/@react-native-community/cli/.*/.* 20 | 21 | [include] 22 | 23 | [libs] 24 | node_modules/react-native/Libraries/react-native/react-native-interface.js 25 | node_modules/react-native/flow/ 26 | 27 | [options] 28 | emoji=true 29 | 30 | esproposal.optional_chaining=enable 31 | esproposal.nullish_coalescing=enable 32 | 33 | module.file_ext=.js 34 | module.file_ext=.json 35 | module.file_ext=.ios.js 36 | 37 | munge_underscores=true 38 | 39 | module.name_mapper='^react-native$' -> '/node_modules/react-native/Libraries/react-native/react-native-implementation' 40 | module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1' 41 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub' 42 | 43 | suppress_type=$FlowIssue 44 | suppress_type=$FlowFixMe 45 | suppress_type=$FlowFixMeProps 46 | suppress_type=$FlowFixMeState 47 | 48 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ 50 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 51 | 52 | [lints] 53 | sketchy-null-number=warn 54 | sketchy-null-mixed=warn 55 | sketchy-number=warn 56 | untyped-type-import=warn 57 | nonstrict-import=warn 58 | deprecated-type=warn 59 | unsafe-getters-setters=warn 60 | inexact-spread=warn 61 | unnecessary-invariant=warn 62 | signature-verification-failure=warn 63 | deprecated-utility=error 64 | 65 | [strict] 66 | deprecated-type 67 | nonstrict-import 68 | sketchy-null 69 | unclear-type 70 | unsafe-getters-setters 71 | untyped-import 72 | untyped-type-import 73 | 74 | [version] 75 | ^0.105.0 76 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Presentable/PanModalPresentable+UIViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanModalPresentable+UIViewController.swift 3 | // PanModal 4 | // 5 | // Copyright © 2018 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | Extends PanModalPresentable with helper methods 13 | when the conforming object is a UIViewController 14 | */ 15 | public extension PanModalPresentable where Self: UIViewController { 16 | 17 | typealias AnimationBlockType = () -> Void 18 | typealias AnimationCompletionType = (Bool) -> Void 19 | 20 | /** 21 | For Presentation, the object must be a UIViewController & confrom to the PanModalPresentable protocol. 22 | */ 23 | typealias LayoutType = UIViewController & PanModalPresentable 24 | 25 | /** 26 | A function wrapper over the `transition(to state: PanModalPresentationController.PresentationState)` 27 | function in the PanModalPresentationController. 28 | */ 29 | func panModalTransition(to state: PanModalPresentationController.PresentationState) { 30 | presentedVC?.transition(to: state) 31 | } 32 | 33 | /** 34 | A function wrapper over the `setNeedsLayoutUpdate()` 35 | function in the PanModalPresentationController. 36 | 37 | - Note: This should be called whenever any of the values for the PanModalPresentable protocol are changed. 38 | */ 39 | func panModalSetNeedsLayoutUpdate() { 40 | presentedVC?.setNeedsLayoutUpdate() 41 | } 42 | 43 | /** 44 | Operations on the scroll view, such as content height changes, or when inserting/deleting rows can cause the pan modal to jump, 45 | caused by the pan modal responding to content offset changes. 46 | 47 | To avoid this, you can call this method to perform scroll view updates, with scroll observation temporarily disabled. 48 | */ 49 | func panModalPerformUpdates(_ updates: () -> Void) { 50 | presentedVC?.performUpdates(updates) 51 | } 52 | 53 | /** 54 | A function wrapper over the animate function in PanModalAnimator. 55 | 56 | This can be used for animation consistency on views within the presented view controller. 57 | */ 58 | func panModalAnimate(_ animationBlock: @escaping AnimationBlockType, _ completion: AnimationCompletionType? = nil) { 59 | PanModalAnimator.animate(animationBlock, config: self, completion) 60 | } 61 | 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/samplemaps/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.samplemaps; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import com.facebook.react.PackageList; 6 | import com.facebook.react.ReactApplication; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.soloader.SoLoader; 10 | import java.lang.reflect.InvocationTargetException; 11 | import java.util.List; 12 | 13 | public class MainApplication extends Application implements ReactApplication { 14 | 15 | private final ReactNativeHost mReactNativeHost = 16 | new ReactNativeHost(this) { 17 | @Override 18 | public boolean getUseDeveloperSupport() { 19 | return BuildConfig.DEBUG; 20 | } 21 | 22 | @Override 23 | protected List getPackages() { 24 | @SuppressWarnings("UnnecessaryLocalVariable") 25 | List packages = new PackageList(this).getPackages(); 26 | // Packages that cannot be autolinked yet can be added manually here, for example: 27 | // packages.add(new MyReactNativePackage()); 28 | return packages; 29 | } 30 | 31 | @Override 32 | protected String getJSMainModuleName() { 33 | return "index"; 34 | } 35 | }; 36 | 37 | @Override 38 | public ReactNativeHost getReactNativeHost() { 39 | return mReactNativeHost; 40 | } 41 | 42 | @Override 43 | public void onCreate() { 44 | super.onCreate(); 45 | SoLoader.init(this, /* native exopackage */ false); 46 | initializeFlipper(this); // Remove this line if you don't want Flipper enabled 47 | } 48 | 49 | /** 50 | * Loads Flipper in React Native templates. 51 | * 52 | * @param context 53 | */ 54 | private static void initializeFlipper(Context context) { 55 | if (BuildConfig.DEBUG) { 56 | try { 57 | /* 58 | We use reflection here to pick up the class that initializes Flipper, 59 | since Flipper library is not available in release mode 60 | */ 61 | Class aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper"); 62 | aClass.getMethod("initializeFlipper", Context.class).invoke(null, context); 63 | } catch (ClassNotFoundException e) { 64 | e.printStackTrace(); 65 | } catch (NoSuchMethodException e) { 66 | e.printStackTrace(); 67 | } catch (IllegalAccessException e) { 68 | e.printStackTrace(); 69 | } catch (InvocationTargetException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/SampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SampleViewController.swift 3 | // PanModal 4 | // 5 | // Created by Stephen Sowole on 10/9/18. 6 | // Copyright © 2018 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | 12 | @objc class SampleViewController: UIViewController { 13 | 14 | 15 | @objc public init() { 16 | super.init(nibName:nil, bundle:nil) 17 | // DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { 18 | // self.presentPanModal() 19 | // } 20 | } 21 | 22 | 23 | required init(coder aDecoder: NSCoder) { 24 | fatalError("init(coder:) has not been implemented") 25 | } 26 | 27 | } 28 | 29 | protocol RowPresentable { 30 | var string: String { get } 31 | var rowVC: UIViewController & PanModalPresentable { get } 32 | } 33 | 34 | private extension SampleViewController { 35 | 36 | enum RowType: Int, CaseIterable { 37 | case basic 38 | case fullScreen 39 | case alert 40 | case transientAlert 41 | case userGroups 42 | case stacked 43 | case navController 44 | 45 | 46 | var presentable: RowPresentable { 47 | switch self { 48 | case .basic: return Basic() 49 | case .fullScreen: return FullScreen() 50 | case .alert: return Alert() 51 | case .transientAlert: return TransientAlert() 52 | case .userGroups: return UserGroup() 53 | case .stacked: return Stacked() 54 | case .navController: return UserGroup() 55 | } 56 | } 57 | 58 | struct Basic: RowPresentable { 59 | let string: String = "Basic" 60 | let rowVC: PanModalPresentable.LayoutType = BasicViewController() 61 | } 62 | 63 | struct FullScreen: RowPresentable { 64 | let string: String = "Full Screen" 65 | let rowVC: PanModalPresentable.LayoutType = FullScreenNavController() 66 | } 67 | 68 | struct Alert: RowPresentable { 69 | let string: String = "Alert" 70 | let rowVC: PanModalPresentable.LayoutType = AlertViewController() 71 | } 72 | 73 | struct TransientAlert: RowPresentable { 74 | let string: String = "Alert (Transient)" 75 | let rowVC: PanModalPresentable.LayoutType = TransientAlertViewController() 76 | } 77 | 78 | struct UserGroup: RowPresentable { 79 | let string: String = "User Groups" 80 | let rowVC: PanModalPresentable.LayoutType = AlertViewController() 81 | } 82 | 83 | struct Stacked: RowPresentable { 84 | let string: String = "User Groups (Stacked)" 85 | let rowVC: PanModalPresentable.LayoutType = UserGroupStackedViewController() 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/User Groups (Navigation Controller)/NavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationController.swift 3 | // PanModal 4 | // 5 | // Created by Stephen Sowole on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NavigationController: UINavigationController, PanModalPresentable { 12 | 13 | private let navGroups = NavUserGroups() 14 | 15 | init() { 16 | super.init(nibName: nil, bundle: nil) 17 | viewControllers = [navGroups] 18 | } 19 | 20 | required init?(coder aDecoder: NSCoder) { 21 | fatalError() 22 | } 23 | 24 | override var preferredStatusBarStyle: UIStatusBarStyle { 25 | return .lightContent 26 | } 27 | 28 | override func popViewController(animated: Bool) -> UIViewController? { 29 | let vc = super.popViewController(animated: animated) 30 | panModalSetNeedsLayoutUpdate() 31 | return vc 32 | } 33 | 34 | override func pushViewController(_ viewController: UIViewController, animated: Bool) { 35 | super.pushViewController(viewController, animated: animated) 36 | panModalSetNeedsLayoutUpdate() 37 | } 38 | 39 | // MARK: - Pan Modal Presentable 40 | 41 | var panScrollable: UIScrollView? { 42 | return (topViewController as? PanModalPresentable)?.panScrollable 43 | } 44 | 45 | var longFormHeight: PanModalHeight { 46 | return .maxHeight 47 | } 48 | 49 | var shortFormHeight: PanModalHeight { 50 | return longFormHeight 51 | } 52 | } 53 | 54 | private class NavUserGroups: UserGroupViewController { 55 | 56 | override func viewDidLoad() { 57 | super.viewDidLoad() 58 | 59 | title = "iOS Engineers" 60 | 61 | navigationController?.navigationBar.isTranslucent = false 62 | navigationController?.navigationBar.titleTextAttributes = [ 63 | .font: UIFont(name: "Lato-Bold", size: 17)!, 64 | .foregroundColor: #colorLiteral(red: 0.7019607843, green: 0.7058823529, blue: 0.7137254902, alpha: 1) 65 | ] 66 | navigationController?.navigationBar.tintColor = #colorLiteral(red: 0.7019607843, green: 0.7058823529, blue: 0.7137254902, alpha: 1) 67 | navigationController?.navigationBar.barTintColor = #colorLiteral(red: 0.1294117647, green: 0.1411764706, blue: 0.1568627451, alpha: 1) 68 | 69 | navigationItem.backBarButtonItem = UIBarButtonItem(title:"", style: .plain, target: nil, action: nil) 70 | } 71 | 72 | // override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 73 | // tableView.deselectRow(at: indexPath, animated: true) 74 | // 75 | // let presentable = members[indexPath.row] 76 | // let viewController = ProfileViewController(presentable: presentable) 77 | // 78 | // navigationController?.pushViewController(viewController, animated: true) 79 | // } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '10.0' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | target 'samplemaps' do 5 | # Pods for samplemaps 6 | pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" 7 | pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" 8 | pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" 9 | pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" 10 | pod 'React', :path => '../node_modules/react-native/' 11 | pod 'React-Core', :path => '../node_modules/react-native/' 12 | pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' 13 | pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' 14 | pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' 15 | pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' 16 | pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' 17 | pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' 18 | pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' 19 | pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' 20 | pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' 21 | pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' 22 | pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' 23 | pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' 24 | 25 | pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' 26 | pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' 27 | pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' 28 | pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' 29 | pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon" 30 | pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" 31 | pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga' 32 | 33 | pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' 34 | pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' 35 | pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' 36 | 37 | pod 'PanModal' 38 | 39 | target 'samplemapsTests' do 40 | inherit! :search_paths 41 | # Pods for testing 42 | end 43 | 44 | use_native_modules! 45 | end 46 | 47 | target 'samplemaps-tvOS' do 48 | # Pods for samplemaps-tvOS 49 | 50 | target 'samplemaps-tvOSTests' do 51 | inherit! :search_paths 52 | # Pods for testing 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/User Groups (Navigation Controller)/ProfileViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProfileViewController.swift 3 | // PanModal 4 | // 5 | // Created by Tosin Afolabi on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ProfileViewController: UIViewController { 12 | 13 | // MARK: - Properties 14 | 15 | let presentable: UserGroupMemberPresentable 16 | 17 | // MARK: - Views 18 | 19 | let avatarView: UIView = { 20 | let view = UIView() 21 | view.layer.cornerRadius = 6.0 22 | view.translatesAutoresizingMaskIntoConstraints = false 23 | return view 24 | }() 25 | 26 | let nameLabel: UILabel = { 27 | let label = UILabel() 28 | label.textColor = #colorLiteral(red: 0.8196078431, green: 0.8235294118, blue: 0.8274509804, alpha: 1) 29 | label.font = UIFont(name: "Lato-Bold", size: 20.0) 30 | label.backgroundColor = .clear 31 | label.translatesAutoresizingMaskIntoConstraints = false 32 | return label 33 | }() 34 | 35 | let roleLabel: UILabel = { 36 | let label = UILabel() 37 | label.textColor = #colorLiteral(red: 0.7019607843, green: 0.7058823529, blue: 0.7137254902, alpha: 1) 38 | label.backgroundColor = .clear 39 | label.font = UIFont(name: "Lato-Regular", size: 16.0) 40 | label.translatesAutoresizingMaskIntoConstraints = false 41 | return label 42 | }() 43 | 44 | // MARK: - Initializers 45 | 46 | init(presentable: UserGroupMemberPresentable) { 47 | self.presentable = presentable 48 | super.init(nibName: nil, bundle: nil) 49 | } 50 | 51 | required init?(coder aDecoder: NSCoder) { 52 | fatalError("init(coder:) has not been implemented") 53 | } 54 | 55 | // MARK: - View Lifecycle 56 | 57 | override func viewDidLoad() { 58 | super.viewDidLoad() 59 | 60 | title = "Profile" 61 | view.backgroundColor = #colorLiteral(red: 0.1019607843, green: 0.1137254902, blue: 0.1294117647, alpha: 1) 62 | 63 | view.addSubview(avatarView) 64 | view.addSubview(nameLabel) 65 | view.addSubview(roleLabel) 66 | 67 | nameLabel.text = presentable.name 68 | roleLabel.text = presentable.role 69 | avatarView.backgroundColor = presentable.avatarBackgroundColor 70 | 71 | setupConstraints() 72 | } 73 | 74 | // MARK: - Layoutt 75 | 76 | func setupConstraints() { 77 | 78 | avatarView.widthAnchor.constraint(equalToConstant: 200.0).isActive = true 79 | avatarView.heightAnchor.constraint(equalToConstant: 200.0).isActive = true 80 | avatarView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 81 | avatarView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100.0).isActive = true 82 | 83 | nameLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 84 | nameLabel.topAnchor.constraint(equalTo: avatarView.bottomAnchor, constant: 60.0).isActive = true 85 | 86 | roleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 87 | roleLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 8.0).isActive = true 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem http://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/Alert/AlertView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlertView.swift 3 | // PanModal 4 | // 5 | // Created by Stephen Sowole on 3/1/19. 6 | // Copyright © 2019 Detail. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class AlertView: UIView { 12 | 13 | // MARK: - Views 14 | 15 | private let colors = [#colorLiteral(red: 0.7215686275, green: 0.9098039216, blue: 0.5607843137, alpha: 1), #colorLiteral(red: 0.7176470588, green: 0.8784313725, blue: 0.9882352941, alpha: 1), #colorLiteral(red: 0.9725490196, green: 0.937254902, blue: 0.4666666667, alpha: 1), #colorLiteral(red: 0.9490196078, green: 0.7568627451, blue: 0.9803921569, alpha: 1), #colorLiteral(red: 0.9960784314, green: 0.8823529412, blue: 0.6980392157, alpha: 1)] 16 | 17 | private lazy var icon: UIView = { 18 | let icon = UIView() 19 | icon.backgroundColor = colors.randomElement() 20 | icon.layer.cornerRadius = 6.0 21 | return icon 22 | }() 23 | 24 | let titleLabel: UILabel = { 25 | let label = UILabel() 26 | label.text = "Incoming Message" 27 | label.font = UIFont(name: "Lato-Bold", size: 17.0) 28 | label.textColor = #colorLiteral(red: 0.8196078431, green: 0.8235294118, blue: 0.8274509804, alpha: 1) 29 | return label 30 | }() 31 | 32 | let message: UILabel = { 33 | let label = UILabel() 34 | label.text = "This is an example alert..." 35 | label.font = UIFont(name: "Lato-Regular", size: 13.0) 36 | label.textColor = #colorLiteral(red: 0.7019607843, green: 0.7058823529, blue: 0.7137254902, alpha: 1) 37 | return label 38 | }() 39 | 40 | private lazy var alertStackView: UIStackView = { 41 | let stackView = UIStackView(arrangedSubviews: [titleLabel, message]) 42 | stackView.axis = .vertical 43 | stackView.alignment = .leading 44 | stackView.spacing = 4.0 45 | return stackView 46 | }() 47 | 48 | init() { 49 | super.init(frame: .zero) 50 | setupView() 51 | } 52 | 53 | required init?(coder aDecoder: NSCoder) { 54 | fatalError("init(coder:) has not been implemented") 55 | } 56 | 57 | // MARK: - Layout 58 | 59 | private func setupView() { 60 | backgroundColor = #colorLiteral(red: 0.1019607843, green: 0.1137254902, blue: 0.1294117647, alpha: 1) 61 | layoutIcon() 62 | layoutStackView() 63 | } 64 | 65 | private func layoutIcon() { 66 | addSubview(icon) 67 | icon.translatesAutoresizingMaskIntoConstraints = false 68 | icon.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 14).isActive = true 69 | icon.topAnchor.constraint(equalTo: topAnchor, constant: 14).isActive = true 70 | icon.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -14).isActive = true 71 | icon.widthAnchor.constraint(equalTo: icon.heightAnchor).isActive = true 72 | } 73 | 74 | private func layoutStackView() { 75 | addSubview(alertStackView) 76 | alertStackView.translatesAutoresizingMaskIntoConstraints = false 77 | alertStackView.topAnchor.constraint(equalTo: icon.topAnchor).isActive = true 78 | alertStackView.leadingAnchor.constraint(equalTo: icon.trailingAnchor, constant: 10).isActive = true 79 | alertStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -14).isActive = true 80 | alertStackView.bottomAnchor.constraint(equalTo: icon.bottomAnchor).isActive = true 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Delegate/PanModalPresentationDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanModalPresentationDelegate.swift 3 | // PanModal 4 | // 5 | // Copyright © 2019 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | The PanModalPresentationDelegate conforms to the various transition delegates 13 | and vends the appropriate object for each transition controller requested. 14 | 15 | Usage: 16 | ``` 17 | viewController.modalPresentationStyle = .custom 18 | viewController.transitioningDelegate = PanModalPresentationDelegate.default 19 | ``` 20 | */ 21 | public class PanModalPresentationDelegate: NSObject { 22 | 23 | /** 24 | Returns an instance of the delegate, retained for the duration of presentation 25 | */ 26 | public static var `default`: PanModalPresentationDelegate = { 27 | return PanModalPresentationDelegate() 28 | }() 29 | 30 | } 31 | 32 | extension PanModalPresentationDelegate: UIViewControllerTransitioningDelegate { 33 | 34 | /** 35 | Returns a modal presentation animator configured for the presenting state 36 | */ 37 | public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 38 | if #available(iOS 10.0, *) { 39 | return PanModalPresentationAnimator(transitionStyle: .presentation) 40 | } else { 41 | return nil 42 | } 43 | } 44 | 45 | /** 46 | Returns a modal presentation animator configured for the dismissing state 47 | */ 48 | public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 49 | if #available(iOS 10.0, *) { 50 | return PanModalPresentationAnimator(transitionStyle: .dismissal) 51 | } else { 52 | return nil 53 | } 54 | } 55 | 56 | /** 57 | Returns a modal presentation controller to coordinate the transition from the presenting 58 | view controller to the presented view controller. 59 | 60 | Changes in size class during presentation are handled via the adaptive presentation delegate 61 | */ 62 | public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { 63 | let controller = PanModalPresentationController(presentedViewController: presented, presenting: presenting) 64 | controller.delegate = self 65 | return controller 66 | } 67 | 68 | } 69 | 70 | extension PanModalPresentationDelegate: UIAdaptivePresentationControllerDelegate, UIPopoverPresentationControllerDelegate { 71 | 72 | /** 73 | - Note: We do not adapt to size classes due to the introduction of the UIPresentationController 74 | & deprecation of UIPopoverController (iOS 9), there is no way to have more than one 75 | presentation controller in use during the same presentation 76 | 77 | This is essential when transitioning from .popover to .custom on iPad split view... unless a custom popover view is also implemented 78 | (popover uses UIPopoverPresentationController & we use PanModalPresentationController) 79 | */ 80 | 81 | /** 82 | Dismisses the presented view controller 83 | */ 84 | public func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { 85 | return .none 86 | } 87 | 88 | } 89 | #endif 90 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/User Groups/Views/UserGroupHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserGroupHeaderView.swift 3 | // PanModal 4 | // 5 | // Created by Tosin Afolabi on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class UserGroupHeaderView: UIView { 12 | 13 | struct Constants { 14 | static let contentInsets = UIEdgeInsets(top: 12.0, left: 16.0, bottom: 12.0, right: 16.0) 15 | } 16 | 17 | // MARK: - Views 18 | 19 | let titleLabel: UILabel = { 20 | let label = UILabel() 21 | label.font = UIFont(name: "Lato-Bold", size: 17.0) 22 | label.textColor = #colorLiteral(red: 0.8196078431, green: 0.8235294118, blue: 0.8274509804, alpha: 1) 23 | return label 24 | }() 25 | 26 | let subtitleLabel: UILabel = { 27 | let label = UILabel() 28 | label.numberOfLines = 2 29 | label.textColor = #colorLiteral(red: 0.7019607843, green: 0.7058823529, blue: 0.7137254902, alpha: 1) 30 | label.font = UIFont(name: "Lato-Regular", size: 13.0) 31 | return label 32 | }() 33 | 34 | lazy var stackView: UIStackView = { 35 | let stackView = UIStackView(arrangedSubviews: [titleLabel, subtitleLabel]) 36 | stackView.axis = .vertical 37 | stackView.alignment = .leading 38 | stackView.spacing = 4.0 39 | stackView.translatesAutoresizingMaskIntoConstraints = false 40 | return stackView 41 | }() 42 | 43 | let seperatorView: UIView = { 44 | let view = UIView() 45 | view.backgroundColor = #colorLiteral(red: 0.8196078431, green: 0.8235294118, blue: 0.8274509804, alpha: 1).withAlphaComponent(0.11) 46 | view.translatesAutoresizingMaskIntoConstraints = false 47 | return view 48 | }() 49 | 50 | // MARK: - Initializers 51 | 52 | override init(frame: CGRect) { 53 | super.init(frame: frame) 54 | 55 | backgroundColor = #colorLiteral(red: 0.1019607843, green: 0.1137254902, blue: 0.1294117647, alpha: 1) 56 | 57 | addSubview(stackView) 58 | addSubview(seperatorView) 59 | 60 | setupConstraints() 61 | } 62 | 63 | required init?(coder aDecoder: NSCoder) { 64 | fatalError("init(coder:) has not been implemented") 65 | } 66 | 67 | // MARK: - Layout 68 | 69 | func setupConstraints() { 70 | 71 | stackView.topAnchor.constraint(equalTo: topAnchor, constant: Constants.contentInsets.top).isActive = true 72 | stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: Constants.contentInsets.left).isActive = true 73 | stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Constants.contentInsets.right).isActive = true 74 | stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -Constants.contentInsets.bottom).isActive = true 75 | 76 | seperatorView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true 77 | seperatorView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true 78 | seperatorView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true 79 | seperatorView.heightAnchor.constraint(equalToConstant: 1.0).isActive = true 80 | } 81 | 82 | // MARK: - View Configuration 83 | 84 | func configure(with presentable: UserGroupHeaderPresentable) { 85 | titleLabel.text = "@\(presentable.handle)" 86 | subtitleLabel.text = "\(presentable.memberCount) members | \(presentable.description)" 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Presentable/PanModalPresentable+Defaults.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanModalPresentable+Defaults.swift 3 | // PanModal 4 | // 5 | // Copyright © 2018 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | Default values for the PanModalPresentable. 13 | */ 14 | public extension PanModalPresentable where Self: UIViewController { 15 | 16 | var topOffset: CGFloat { 17 | return topLayoutOffset + 21.0 18 | } 19 | 20 | var shortFormHeight: PanModalHeight { 21 | return longFormHeight 22 | } 23 | 24 | var longFormHeight: PanModalHeight { 25 | 26 | guard let scrollView = panScrollable 27 | else { return .maxHeight } 28 | 29 | // called once during presentation and stored 30 | scrollView.layoutIfNeeded() 31 | return .contentHeight(scrollView.contentSize.height) 32 | } 33 | 34 | var cornerRadius: CGFloat { 35 | return 8.0 36 | } 37 | 38 | var springDamping: CGFloat { 39 | return 0.8 40 | } 41 | 42 | var transitionDuration: Double { 43 | return PanModalAnimator.Constants.defaultTransitionDuration 44 | } 45 | 46 | var transitionAnimationOptions: UIView.AnimationOptions { 47 | return [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState] 48 | } 49 | 50 | var panModalBackgroundColor: UIColor { 51 | return UIColor.black.withAlphaComponent(0.7) 52 | } 53 | 54 | var dragIndicatorBackgroundColor: UIColor { 55 | return UIColor.lightGray 56 | } 57 | 58 | var scrollIndicatorInsets: UIEdgeInsets { 59 | let top = shouldRoundTopCorners ? cornerRadius : 0 60 | return UIEdgeInsets(top: CGFloat(top), left: 0, bottom: bottomLayoutOffset, right: 0) 61 | } 62 | 63 | var anchorModalToLongForm: Bool { 64 | return true 65 | } 66 | 67 | var allowsExtendedPanScrolling: Bool { 68 | 69 | guard let scrollView = panScrollable 70 | else { return false } 71 | 72 | scrollView.layoutIfNeeded() 73 | return scrollView.contentSize.height > (scrollView.frame.height - bottomLayoutOffset) 74 | } 75 | 76 | var allowsDragToDismiss: Bool { 77 | return true 78 | } 79 | 80 | var allowsTapToDismiss: Bool { 81 | return true 82 | } 83 | 84 | var isUserInteractionEnabled: Bool { 85 | return true 86 | } 87 | 88 | var isHapticFeedbackEnabled: Bool { 89 | return true 90 | } 91 | 92 | var shouldRoundTopCorners: Bool { 93 | return isPanModalPresented 94 | } 95 | 96 | var showDragIndicator: Bool { 97 | return shouldRoundTopCorners 98 | } 99 | 100 | func shouldRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool { 101 | return true 102 | } 103 | 104 | func willRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) { 105 | 106 | } 107 | 108 | func shouldTransition(to state: PanModalPresentationController.PresentationState) -> Bool { 109 | return true 110 | } 111 | 112 | func shouldPrioritize(panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool { 113 | return false 114 | } 115 | 116 | func willTransition(to state: PanModalPresentationController.PresentationState) { 117 | 118 | } 119 | 120 | func panModalWillDismiss() { 121 | 122 | } 123 | 124 | func panModalDidDismiss() { 125 | 126 | } 127 | } 128 | #endif 129 | -------------------------------------------------------------------------------- /ios/samplemaps/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Presentable/PanModalPresentable+LayoutHelpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanModalPresentable+LayoutHelpers.swift 3 | // PanModal 4 | // 5 | // Copyright © 2018 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | ⚠️ [Internal Only] ⚠️ 13 | Helper extensions that handle layout in the PanModalPresentationController 14 | */ 15 | extension PanModalPresentable where Self: UIViewController { 16 | 17 | /** 18 | Cast the presentation controller to PanModalPresentationController 19 | so we can access PanModalPresentationController properties and methods 20 | */ 21 | var presentedVC: PanModalPresentationController? { 22 | return presentationController as? PanModalPresentationController 23 | } 24 | 25 | /** 26 | Length of the top layout guide of the presenting view controller. 27 | Gives us the safe area inset from the top. 28 | */ 29 | var topLayoutOffset: CGFloat { 30 | return UIApplication.shared.keyWindow?.rootViewController?.topLayoutGuide.length ?? 0 31 | } 32 | 33 | /** 34 | Length of the bottom layout guide of the presenting view controller. 35 | Gives us the safe area inset from the bottom. 36 | */ 37 | var bottomLayoutOffset: CGFloat { 38 | return UIApplication.shared.keyWindow?.rootViewController?.bottomLayoutGuide.length ?? 0 39 | } 40 | 41 | /** 42 | Returns the short form Y position 43 | 44 | - Note: If voiceover is on, the `longFormYPos` is returned. 45 | We do not support short form when voiceover is on as it would make it difficult for user to navigate. 46 | */ 47 | var shortFormYPos: CGFloat { 48 | 49 | guard !UIAccessibility.isVoiceOverRunning 50 | else { return longFormYPos } 51 | 52 | let shortFormYPos = topMargin(from: shortFormHeight) + topOffset 53 | 54 | // shortForm shouldn't exceed longForm 55 | return max(shortFormYPos, longFormYPos) 56 | } 57 | 58 | /** 59 | Returns the long form Y position 60 | 61 | - Note: We cap this value to the max possible height 62 | to ensure content is not rendered outside of the view bounds 63 | */ 64 | var longFormYPos: CGFloat { 65 | return max(topMargin(from: longFormHeight), topMargin(from: .maxHeight)) + topOffset 66 | } 67 | 68 | /** 69 | Use the container view for relative positioning as this view's frame 70 | is adjusted in PanModalPresentationController 71 | */ 72 | var bottomYPos: CGFloat { 73 | 74 | guard let container = presentedVC?.containerView 75 | else { return view.bounds.height } 76 | 77 | return container.bounds.size.height - topOffset 78 | } 79 | 80 | /** 81 | Converts a given pan modal height value into a y position value 82 | calculated from top of view 83 | */ 84 | func topMargin(from: PanModalHeight) -> CGFloat { 85 | switch from { 86 | case .maxHeight: 87 | return 0.0 88 | case .maxHeightWithTopInset(let inset): 89 | return inset 90 | case .contentHeight(let height): 91 | return bottomYPos - (height + bottomLayoutOffset) 92 | case .contentHeightIgnoringSafeArea(let height): 93 | return bottomYPos - height 94 | case .intrinsicHeight: 95 | view.layoutIfNeeded() 96 | let targetSize = CGSize(width: (presentedVC?.containerView?.bounds ?? UIScreen.main.bounds).width, 97 | height: UIView.layoutFittingCompressedSize.height) 98 | let intrinsicHeight = view.systemLayoutSizeFitting(targetSize).height 99 | return bottomYPos - (intrinsicHeight + bottomLayoutOffset) 100 | } 101 | } 102 | 103 | } 104 | #endif 105 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/User Groups (Stacked)/StackedProfileViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackedProfileViewController.swift 3 | // PanModal 4 | // 5 | // Created by Tosin Afolabi on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class StackedProfileViewController: UIViewController, PanModalPresentable { 12 | 13 | // MARK: - Properties 14 | 15 | let presentable: UserGroupMemberPresentable 16 | 17 | override var preferredStatusBarStyle: UIStatusBarStyle { 18 | return .lightContent 19 | } 20 | 21 | // MARK: - Views 22 | 23 | let avatarView: UIView = { 24 | let view = UIView() 25 | view.layer.cornerRadius = 6.0 26 | view.translatesAutoresizingMaskIntoConstraints = false 27 | return view 28 | }() 29 | 30 | let nameLabel: UILabel = { 31 | let label = UILabel() 32 | label.textColor = #colorLiteral(red: 0.8196078431, green: 0.8235294118, blue: 0.8274509804, alpha: 1) 33 | label.font = UIFont(name: "Lato-Bold", size: 20.0) 34 | label.backgroundColor = .clear 35 | label.translatesAutoresizingMaskIntoConstraints = false 36 | return label 37 | }() 38 | 39 | let roleLabel: UILabel = { 40 | let label = UILabel() 41 | label.textColor = #colorLiteral(red: 0.7019607843, green: 0.7058823529, blue: 0.7137254902, alpha: 1) 42 | label.backgroundColor = .clear 43 | label.font = UIFont(name: "Lato-Regular", size: 15.0) 44 | label.translatesAutoresizingMaskIntoConstraints = false 45 | return label 46 | }() 47 | 48 | // MARK: - Initializers 49 | 50 | init(presentable: UserGroupMemberPresentable) { 51 | self.presentable = presentable 52 | super.init(nibName: nil, bundle: nil) 53 | } 54 | 55 | required init?(coder aDecoder: NSCoder) { 56 | fatalError("init(coder:) has not been implemented") 57 | } 58 | 59 | // MARK: - View Lifecycle 60 | 61 | override func viewDidLoad() { 62 | super.viewDidLoad() 63 | 64 | title = "Profile" 65 | view.backgroundColor = #colorLiteral(red: 0.1019607843, green: 0.1137254902, blue: 0.1294117647, alpha: 1) 66 | 67 | view.addSubview(avatarView) 68 | view.addSubview(nameLabel) 69 | view.addSubview(roleLabel) 70 | 71 | nameLabel.text = presentable.name 72 | roleLabel.text = presentable.role 73 | avatarView.backgroundColor = presentable.avatarBackgroundColor 74 | 75 | setupConstraints() 76 | } 77 | 78 | // MARK: - Layoutt 79 | 80 | func setupConstraints() { 81 | 82 | avatarView.widthAnchor.constraint(equalToConstant: 200.0).isActive = true 83 | avatarView.heightAnchor.constraint(equalToConstant: 200.0).isActive = true 84 | avatarView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 85 | avatarView.topAnchor.constraint(equalTo: view.topAnchor, constant: 25.0).isActive = true 86 | 87 | nameLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 88 | nameLabel.topAnchor.constraint(equalTo: avatarView.bottomAnchor, constant: 20.0).isActive = true 89 | 90 | roleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 91 | roleLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 4.0).isActive = true 92 | bottomLayoutGuide.topAnchor.constraint(greaterThanOrEqualTo: roleLabel.bottomAnchor).isActive = true 93 | } 94 | 95 | // MARK: - Pan Modal Presentable 96 | 97 | var panScrollable: UIScrollView? { 98 | return nil 99 | } 100 | 101 | var longFormHeight: PanModalHeight { 102 | return .intrinsicHeight 103 | } 104 | 105 | var anchorModalToLongForm: Bool { 106 | return false 107 | } 108 | 109 | var shouldRoundTopCorners: Bool { 110 | return true 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "57x57", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-57x57@1x.png", 49 | "scale" : "1x" 50 | }, 51 | { 52 | "size" : "57x57", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-57x57@2x.png", 55 | "scale" : "2x" 56 | }, 57 | { 58 | "size" : "60x60", 59 | "idiom" : "iphone", 60 | "filename" : "Icon-App-60x60@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "60x60", 65 | "idiom" : "iphone", 66 | "filename" : "Icon-App-60x60@3x.png", 67 | "scale" : "3x" 68 | }, 69 | { 70 | "size" : "20x20", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-20x20@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "20x20", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-20x20@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "29x29", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-29x29@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "29x29", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-29x29@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "40x40", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-40x40@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "40x40", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-40x40@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "50x50", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-Small-50x50@1x.png", 109 | "scale" : "1x" 110 | }, 111 | { 112 | "size" : "50x50", 113 | "idiom" : "ipad", 114 | "filename" : "Icon-Small-50x50@2x.png", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "size" : "72x72", 119 | "idiom" : "ipad", 120 | "filename" : "Icon-App-72x72@1x.png", 121 | "scale" : "1x" 122 | }, 123 | { 124 | "size" : "72x72", 125 | "idiom" : "ipad", 126 | "filename" : "Icon-App-72x72@2x.png", 127 | "scale" : "2x" 128 | }, 129 | { 130 | "size" : "76x76", 131 | "idiom" : "ipad", 132 | "filename" : "Icon-App-76x76@1x.png", 133 | "scale" : "1x" 134 | }, 135 | { 136 | "size" : "76x76", 137 | "idiom" : "ipad", 138 | "filename" : "Icon-App-76x76@2x.png", 139 | "scale" : "2x" 140 | }, 141 | { 142 | "size" : "83.5x83.5", 143 | "idiom" : "ipad", 144 | "filename" : "Icon-App-83.5x83.5@2x.png", 145 | "scale" : "2x" 146 | }, 147 | { 148 | "size" : "1024x1024", 149 | "idiom" : "ios-marketing", 150 | "filename" : "ItunesArtwork@2x.png", 151 | "scale" : "1x" 152 | } 153 | ], 154 | "info" : { 155 | "version" : 1, 156 | "author" : "xcode" 157 | } 158 | } -------------------------------------------------------------------------------- /ios/PanModule.m: -------------------------------------------------------------------------------- 1 | 2 | #import "AppDelegate.h" 3 | 4 | #import 5 | #import 6 | #import 7 | #import 8 | #import 9 | #import "samplemaps-Swift.h" 10 | #import 11 | #import 12 | #import 13 | #import 14 | 15 | @interface HelperView : UIView 16 | @end 17 | 18 | @implementation HelperView { 19 | __weak UIView *_view; 20 | __weak RCTBridge *_bridge; 21 | } 22 | - (void) setView: (UIView *) view bridge:(RCTBridge *)bridge { 23 | _view = view; 24 | _bridge = bridge; 25 | } 26 | 27 | - (void)layoutSubviews { 28 | [super layoutSubviews]; 29 | [[_bridge uiManager] setSize:self.frame.size forView:_view]; 30 | } 31 | @end 32 | 33 | @interface InvisibleView: UIView 34 | @property (nonatomic, nonnull) NSNumber *topOffset; 35 | @property (nonatomic) BOOL isShortFormEnabled; 36 | @property (nonatomic, nullable) NSNumber *longFormHeight; 37 | @property (nonatomic, nonnull) NSNumber *cornerRadius; 38 | @property (nonatomic, nonnull) NSNumber *springDamping; 39 | @property (nonatomic, nonnull) NSNumber *transitionDuration; 40 | @property (nonatomic) BOOL anchorModalToLongForm; 41 | @property (nonatomic) BOOL allowsDragToDismiss; 42 | @property (nonatomic) BOOL allowsTapToDismiss; 43 | @property (nonatomic) BOOL isUserInteractionEnabled; 44 | @property (nonatomic) BOOL isHapticFeedbackEnabled; 45 | @property (nonatomic) BOOL shouldRoundTopCorners; 46 | @property (nonatomic) BOOL showDragIndicator; 47 | @property (nonatomic, nonnull) NSNumber *headerHeight; 48 | @property (nonatomic, nonnull) NSNumber *shortFormHeight; 49 | @property (nonatomic) BOOL startFromShortForm; 50 | @end 51 | 52 | @implementation InvisibleView { 53 | __weak RCTBridge *_bridge; 54 | BOOL addedSubview; 55 | } 56 | 57 | - (instancetype)initWithBridge:(RCTBridge *)bridge { 58 | if (self = [super init]) { 59 | _bridge = bridge; 60 | _startFromShortForm = false; 61 | _topOffset = [[NSNumber alloc] initWithInt: 42]; 62 | _isShortFormEnabled = true; 63 | _longFormHeight = nil; 64 | _cornerRadius = [[NSNumber alloc] initWithInt: 8.0]; 65 | _springDamping = [[NSNumber alloc] initWithDouble: 0.8]; 66 | _transitionDuration = [[NSNumber alloc] initWithDouble: 0.5]; 67 | _anchorModalToLongForm = true; 68 | _allowsDragToDismiss = true; 69 | _allowsTapToDismiss = true; 70 | _isUserInteractionEnabled = true; 71 | _isHapticFeedbackEnabled = true; 72 | _shouldRoundTopCorners = true; 73 | _showDragIndicator = true; 74 | _headerHeight = [[NSNumber alloc] initWithInt:0]; 75 | _shortFormHeight = [[NSNumber alloc] initWithInt:300];; 76 | _startFromShortForm = false; 77 | 78 | } 79 | return self; 80 | } 81 | 82 | - (void)addSubview:(UIView *)view { 83 | RCTExecuteOnMainQueue(^{ 84 | if (self->addedSubview) { 85 | return; 86 | } 87 | UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController; 88 | object_setClass(view, [HelperView class]); 89 | [(HelperView *)view setView:view bridge:self->_bridge]; 90 | self->addedSubview = YES; 91 | 92 | [rootViewController presentPanModalWithView:view config:self]; 93 | }); 94 | 95 | } 96 | 97 | @end 98 | 99 | @interface ModalViewManager : RCTViewManager 100 | @end 101 | 102 | @implementation ModalViewManager 103 | 104 | RCT_EXPORT_MODULE(ModalView) 105 | RCT_EXPORT_VIEW_PROPERTY(longFormHeight, NSNumber) 106 | RCT_EXPORT_VIEW_PROPERTY(cornerRadius, NSNumber) 107 | RCT_EXPORT_VIEW_PROPERTY(springDamping, NSNumber) 108 | RCT_EXPORT_VIEW_PROPERTY(transitionDuration, NSNumber) 109 | RCT_EXPORT_VIEW_PROPERTY(topOffset, NSNumber) 110 | RCT_EXPORT_VIEW_PROPERTY(headerHeight, NSNumber) 111 | RCT_EXPORT_VIEW_PROPERTY(shortFormHeight, NSNumber) 112 | RCT_EXPORT_VIEW_PROPERTY(isShortFormEnabled, BOOL) 113 | RCT_EXPORT_VIEW_PROPERTY(anchorModalToLongForm, BOOL) 114 | RCT_EXPORT_VIEW_PROPERTY(allowsTapToDismiss, BOOL) 115 | RCT_EXPORT_VIEW_PROPERTY(allowsDragToDismiss, BOOL) 116 | RCT_EXPORT_VIEW_PROPERTY(isUserInteractionEnabled, BOOL) 117 | RCT_EXPORT_VIEW_PROPERTY(isHapticFeedbackEnabled, BOOL) 118 | RCT_EXPORT_VIEW_PROPERTY(shouldRoundTopCorners, BOOL) 119 | RCT_EXPORT_VIEW_PROPERTY(showDragIndicator, BOOL) 120 | RCT_EXPORT_VIEW_PROPERTY(startFromShortForm, BOOL) 121 | 122 | - (UIView *)view { 123 | return [[InvisibleView alloc] initWithBridge:self.bridge]; 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Presenter/UIViewController+PanModalPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+PanModalPresenterProtocol.swift 3 | // PanModal 4 | // 5 | // Copyright © 2019 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | import PanModal 12 | 13 | 14 | class PanModalViewController: UIViewController, PanModalPresentable { 15 | var config: NSObject? 16 | convenience init(config: NSObject) { 17 | self.init() 18 | self.config = config 19 | } 20 | 21 | 22 | override var preferredStatusBarStyle: UIStatusBarStyle { 23 | return .lightContent 24 | } 25 | 26 | func findChildScrollViewDFS(view: UIView)-> UIScrollView? { 27 | var viewsToTraverse = [view] 28 | while !viewsToTraverse.isEmpty { 29 | let last = viewsToTraverse.last! 30 | viewsToTraverse.removeLast() 31 | if last is UIScrollView { 32 | return last as? UIScrollView 33 | } 34 | last.subviews.forEach { subview in 35 | viewsToTraverse.append(subview) 36 | } 37 | } 38 | return nil 39 | } 40 | 41 | 42 | var panScrollable: UIScrollView? { 43 | return findChildScrollViewDFS(view: self.view!) 44 | } 45 | 46 | var shortFormHeight: PanModalHeight { 47 | let height: CGFloat = CGFloat(truncating: self.config?.value(forKey: "shortFormHeight") as! NSNumber) 48 | return isShortFormEnabled ? .contentHeight(height) : longFormHeight 49 | } 50 | 51 | var topOffset: CGFloat { 52 | let topOffset: CGFloat = CGFloat(truncating: self.config?.value(forKey: "topOffset") as! NSNumber) 53 | return topLayoutGuide.length + topOffset 54 | } 55 | 56 | var isShortFormEnabledInternal = 2 57 | var isShortFormEnabled: Bool { 58 | let startFromShortForm = self.config?.value(forKey: "startFromShortForm") as! Bool 59 | if isShortFormEnabledInternal > 0 && !startFromShortForm { 60 | isShortFormEnabledInternal -= 1 61 | return false 62 | } 63 | return self.config?.value(forKey: "isShortFormEnabled") as! Bool 64 | } 65 | 66 | var longFormHeight: PanModalHeight { 67 | if self.config?.value(forKey: "longFormHeight") == nil { 68 | return .maxHeight 69 | } 70 | return .contentHeight(CGFloat(truncating: self.config?.value(forKey: "longFormHeight") as! NSNumber)) 71 | } 72 | 73 | var cornerRadius: CGFloat { 74 | return CGFloat(truncating: self.config?.value(forKey: "cornerRadius") as! NSNumber) 75 | } 76 | 77 | var springDamping: CGFloat { 78 | return CGFloat(truncating: self.config?.value(forKey: "springDamping") as! NSNumber) 79 | } 80 | 81 | var transitionDuration: Double { 82 | return Double(truncating: self.config?.value(forKey: "transitionDuration") as! NSNumber) 83 | } 84 | 85 | var anchorModalToLongForm: Bool { 86 | return self.config?.value(forKey: "anchorModalToLongForm") as! Bool 87 | } 88 | 89 | var allowsDragToDismiss: Bool { 90 | return self.config?.value(forKey: "allowsDragToDismiss") as! Bool 91 | } 92 | 93 | var allowsTapToDismiss: Bool { 94 | return self.config?.value(forKey: "allowsTapToDismiss") as! Bool 95 | } 96 | 97 | var isUserInteractionEnabled: Bool { 98 | return self.config?.value(forKey: "isUserInteractionEnabled") as! Bool } 99 | 100 | var isHapticFeedbackEnabled: Bool { 101 | return self.config?.value(forKey: "isHapticFeedbackEnabled") as! Bool } 102 | 103 | var shouldRoundTopCorners: Bool { 104 | return self.config?.value(forKey: "shouldRoundTopCorners") as! Bool 105 | } 106 | 107 | var showDragIndicator: Bool { 108 | return self.config?.value(forKey: "showDragIndicator") as! Bool 109 | } 110 | 111 | var scrollIndicatorInsets: UIEdgeInsets { 112 | let bottomOffset = presentingViewController?.bottomLayoutGuide.length ?? 0 113 | return UIEdgeInsets(top: 0, left: 0, bottom: bottomOffset, right: 0) 114 | } 115 | 116 | 117 | func shouldPrioritize(panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool { 118 | let headerHeight: CGFloat = CGFloat(truncating: self.config?.value(forKey: "headerHeight") as! NSNumber) 119 | let location = panModalGestureRecognizer.location(in: view) 120 | return location.y < headerHeight 121 | } 122 | 123 | } 124 | 125 | 126 | extension UIViewController { 127 | @objc public func presentPanModal(view: UIView, config: UIView) { 128 | 129 | let viewControllerToPresent: UIViewController & PanModalPresentable = PanModalViewController(config: config) 130 | viewControllerToPresent.view = view 131 | let sourceView: UIView? = nil, sourceRect: CGRect = .zero 132 | 133 | self.presentPanModal(viewControllerToPresent, sourceView: sourceView, sourceRect: sourceRect) 134 | } 135 | 136 | } 137 | #endif 138 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/User Groups/Views/UserGroupMemberCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserGroupMemberCell.swift 3 | // PanModal 4 | // 5 | // Created by Tosin Afolabi on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class UserGroupMemberCell: UITableViewCell { 12 | 13 | struct Constants { 14 | static let contentInsets = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 8.0, right: 16.0) 15 | static let avatarSize = CGSize(width: 36.0, height: 36.0) 16 | } 17 | 18 | // MARK: - Properties 19 | 20 | var presentable = UserGroupMemberPresentable(name: "", role: "", avatarBackgroundColor: .black) 21 | 22 | // MARK: - Views 23 | 24 | let avatarView: UIView = { 25 | let view = UIView() 26 | view.layer.cornerRadius = 8.0 27 | return view 28 | }() 29 | 30 | let nameLabel: UILabel = { 31 | let label = UILabel() 32 | label.textColor = #colorLiteral(red: 0.8196078431, green: 0.8235294118, blue: 0.8274509804, alpha: 1) 33 | label.font = UIFont(name: "Lato-Bold", size: 17.0) 34 | label.backgroundColor = .clear 35 | return label 36 | }() 37 | 38 | let roleLabel: UILabel = { 39 | let label = UILabel() 40 | label.textColor = #colorLiteral(red: 0.7019607843, green: 0.7058823529, blue: 0.7137254902, alpha: 1) 41 | label.backgroundColor = .clear 42 | label.font = UIFont(name: "Lato-Regular", size: 13.0) 43 | return label 44 | }() 45 | 46 | lazy var memberDetailsStackView: UIStackView = { 47 | let stackView = UIStackView(arrangedSubviews: [nameLabel, roleLabel]) 48 | stackView.axis = .vertical 49 | stackView.alignment = .leading 50 | stackView.translatesAutoresizingMaskIntoConstraints = false 51 | return stackView 52 | }() 53 | 54 | lazy var stackView: UIStackView = { 55 | let stackView = UIStackView(arrangedSubviews: [avatarView, memberDetailsStackView]) 56 | stackView.alignment = .center 57 | stackView.spacing = 16.0 58 | stackView.translatesAutoresizingMaskIntoConstraints = false 59 | return stackView 60 | }() 61 | 62 | // MARK: - Initializers 63 | 64 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 65 | super.init(style: style, reuseIdentifier: reuseIdentifier) 66 | 67 | backgroundColor = #colorLiteral(red: 0.1019607843, green: 0.1137254902, blue: 0.1294117647, alpha: 1) 68 | isAccessibilityElement = true 69 | 70 | let backgroundView = UIView() 71 | backgroundView.backgroundColor = #colorLiteral(red: 0.8196078431, green: 0.8235294118, blue: 0.8274509804, alpha: 1).withAlphaComponent(0.11) 72 | selectedBackgroundView = backgroundView 73 | 74 | contentView.addSubview(stackView) 75 | 76 | setupConstraints() 77 | } 78 | 79 | required init?(coder aDecoder: NSCoder) { 80 | fatalError("init(coder:) has not been implemented") 81 | } 82 | 83 | // MARK: - Layout 84 | 85 | func setupConstraints() { 86 | 87 | stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: Constants.contentInsets.top).isActive = true 88 | stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: Constants.contentInsets.left).isActive = true 89 | stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Constants.contentInsets.right).isActive = true 90 | stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -Constants.contentInsets.bottom).isActive = true 91 | 92 | let avatarWidthConstriant = avatarView.widthAnchor.constraint(equalToConstant: Constants.avatarSize.width) 93 | let avatarHeightConstraint = avatarView.heightAnchor.constraint(equalToConstant: Constants.avatarSize.height) 94 | 95 | [avatarWidthConstriant, avatarHeightConstraint].forEach { 96 | $0.priority = UILayoutPriority(UILayoutPriority.required.rawValue - 1) 97 | $0.isActive = true 98 | } 99 | } 100 | 101 | // MARK: - Highlight 102 | 103 | /** 104 | On cell selection or highlight, iOS makes all vies have a clear background 105 | the below methods address the issue for the avatar view 106 | */ 107 | 108 | override func setHighlighted(_ highlighted: Bool, animated: Bool) { 109 | super.setHighlighted(highlighted, animated: animated) 110 | avatarView.backgroundColor = presentable.avatarBackgroundColor 111 | } 112 | 113 | override func setSelected(_ selected: Bool, animated: Bool) { 114 | super.setSelected(selected, animated: animated) 115 | avatarView.backgroundColor = presentable.avatarBackgroundColor 116 | } 117 | 118 | // MARK: - View Configuration 119 | 120 | func configure(with presentable: UserGroupMemberPresentable) { 121 | self.presentable = presentable 122 | nameLabel.text = presentable.name 123 | roleLabel.text = presentable.role 124 | avatarView.backgroundColor = presentable.avatarBackgroundColor 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /ios/samplemaps.xcodeproj/xcshareddata/xcschemes/samplemaps.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/samplemaps.xcodeproj/xcshareddata/xcschemes/samplemaps-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Animator/PanModalPresentationAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanModalPresentationAnimator.swift 3 | // PanModal 4 | // 5 | // Copyright © 2019 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | Handles the animation of the presentedViewController as it is presented or dismissed. 13 | 14 | This is a vertical animation that 15 | - Animates up from the bottom of the screen 16 | - Dismisses from the top to the bottom of the screen 17 | 18 | This can be used as a standalone object for transition animation, 19 | but is primarily used in the PanModalPresentationDelegate for handling pan modal transitions. 20 | 21 | - Note: The presentedViewController can conform to PanModalPresentable to adjust 22 | it's starting position through manipulating the shortFormHeight 23 | */ 24 | 25 | @available(iOS 10.0, *) 26 | public class PanModalPresentationAnimator: NSObject { 27 | 28 | /** 29 | Enum representing the possible transition styles 30 | */ 31 | public enum TransitionStyle { 32 | case presentation 33 | case dismissal 34 | } 35 | 36 | // MARK: - Properties 37 | 38 | /** 39 | The transition style 40 | */ 41 | private let transitionStyle: TransitionStyle 42 | 43 | /** 44 | Haptic feedback generator (during presentation) 45 | */ 46 | private var feedbackGenerator: UISelectionFeedbackGenerator? 47 | 48 | // MARK: - Initializers 49 | 50 | required public init(transitionStyle: TransitionStyle) { 51 | self.transitionStyle = transitionStyle 52 | super.init() 53 | 54 | /** 55 | Prepare haptic feedback, only during the presentation state 56 | */ 57 | if case .presentation = transitionStyle { 58 | feedbackGenerator = UISelectionFeedbackGenerator() 59 | feedbackGenerator?.prepare() 60 | } 61 | } 62 | 63 | /** 64 | Animate presented view controller presentation 65 | */ 66 | private func animatePresentation(transitionContext: UIViewControllerContextTransitioning) { 67 | 68 | guard 69 | let toVC = transitionContext.viewController(forKey: .to), 70 | let fromVC = transitionContext.viewController(forKey: .from) 71 | else { return } 72 | 73 | let presentable = panModalLayoutType(from: transitionContext) 74 | 75 | // Calls viewWillAppear and viewWillDisappear 76 | fromVC.beginAppearanceTransition(false, animated: true) 77 | 78 | // Presents the view in shortForm position, initially 79 | let yPos: CGFloat = presentable?.shortFormYPos ?? 0.0 80 | 81 | // Use panView as presentingView if it already exists within the containerView 82 | let panView: UIView = transitionContext.containerView.panContainerView ?? toVC.view 83 | 84 | // Move presented view offscreen (from the bottom) 85 | panView.frame = transitionContext.finalFrame(for: toVC) 86 | panView.frame.origin.y = transitionContext.containerView.frame.height 87 | 88 | // Haptic feedback 89 | if presentable?.isHapticFeedbackEnabled == true { 90 | feedbackGenerator?.selectionChanged() 91 | } 92 | 93 | PanModalAnimator.animate({ 94 | panView.frame.origin.y = yPos 95 | }, config: presentable) { [weak self] didComplete in 96 | // Calls viewDidAppear and viewDidDisappear 97 | fromVC.endAppearanceTransition() 98 | transitionContext.completeTransition(didComplete) 99 | self?.feedbackGenerator = nil 100 | } 101 | } 102 | 103 | /** 104 | Animate presented view controller dismissal 105 | */ 106 | private func animateDismissal(transitionContext: UIViewControllerContextTransitioning) { 107 | 108 | guard 109 | let toVC = transitionContext.viewController(forKey: .to), 110 | let fromVC = transitionContext.viewController(forKey: .from) 111 | else { return } 112 | 113 | // Calls viewWillAppear and viewWillDisappear 114 | toVC.beginAppearanceTransition(true, animated: true) 115 | 116 | let presentable = panModalLayoutType(from: transitionContext) 117 | let panView: UIView = transitionContext.containerView.panContainerView ?? fromVC.view 118 | 119 | PanModalAnimator.animate({ 120 | panView.frame.origin.y = transitionContext.containerView.frame.height 121 | }, config: presentable) { didComplete in 122 | fromVC.view.removeFromSuperview() 123 | // Calls viewDidAppear and viewDidDisappear 124 | toVC.endAppearanceTransition() 125 | transitionContext.completeTransition(didComplete) 126 | } 127 | } 128 | 129 | /** 130 | Extracts the PanModal from the transition context, if it exists 131 | */ 132 | private func panModalLayoutType(from context: UIViewControllerContextTransitioning) -> PanModalPresentable.LayoutType? { 133 | switch transitionStyle { 134 | case .presentation: 135 | return context.viewController(forKey: .to) as? PanModalPresentable.LayoutType 136 | case .dismissal: 137 | return context.viewController(forKey: .from) as? PanModalPresentable.LayoutType 138 | } 139 | } 140 | 141 | } 142 | 143 | // MARK: - UIViewControllerAnimatedTransitioning Delegate 144 | 145 | @available(iOS 10.0, *) 146 | extension PanModalPresentationAnimator: UIViewControllerAnimatedTransitioning { 147 | 148 | /** 149 | Returns the transition duration 150 | */ 151 | public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 152 | 153 | guard 154 | let context = transitionContext, 155 | let presentable = panModalLayoutType(from: context) 156 | else { return PanModalAnimator.Constants.defaultTransitionDuration } 157 | 158 | return presentable.transitionDuration 159 | } 160 | 161 | /** 162 | Performs the appropriate animation based on the transition style 163 | */ 164 | public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 165 | switch transitionStyle { 166 | case .presentation: 167 | animatePresentation(transitionContext: transitionContext) 168 | case .dismissal: 169 | animateDismissal(transitionContext: transitionContext) 170 | } 171 | } 172 | 173 | } 174 | #endif 175 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin, switch paths to Windows format before running java 129 | if $cygwin ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /ios/samplemaps/Sample/View Controllers/User Groups/UserGroupViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserGroupViewController.swift 3 | // PanModal 4 | // 5 | // Created by Tosin Afolabi on 2/26/19. 6 | // Copyright © 2019 PanModal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import PanModal 12 | 13 | class UserGroupViewController: UIViewController, PanModalPresentable { 14 | 15 | 16 | let members: [UserGroupMemberPresentable] = [ 17 | UserGroupMemberPresentable(name: "Naida Schill ✈️", role: "Staff Engineer - Mobile DevXP", avatarBackgroundColor: #colorLiteral(red: 0.7215686275, green: 0.9098039216, blue: 0.5607843137, alpha: 1)), 18 | UserGroupMemberPresentable(name: "Annalisa Doty", role: "iOS Engineer - NewXP", avatarBackgroundColor: #colorLiteral(red: 0.7176470588, green: 0.8784313725, blue: 0.9882352941, alpha: 1)), 19 | UserGroupMemberPresentable(name: "Petra Gazaway 🏡", role: "Senior iOS Product Engineer - Enterprise", avatarBackgroundColor: #colorLiteral(red: 0.9725490196, green: 0.937254902, blue: 0.4666666667, alpha: 1)), 20 | UserGroupMemberPresentable(name: "Jermaine Gill ⛷", role: "Staff Engineer - Mobile Infra", avatarBackgroundColor: #colorLiteral(red: 0.9490196078, green: 0.7568627451, blue: 0.9803921569, alpha: 1)), 21 | UserGroupMemberPresentable(name: "Juana Brooks 🚌", role: "Staff Software Engineer", avatarBackgroundColor: #colorLiteral(red: 0.9960784314, green: 0.8823529412, blue: 0.6980392157, alpha: 1)), 22 | UserGroupMemberPresentable(name: "Stacey Francis 🛳", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.8784313725, green: 0.8745098039, blue: 0.9921568627, alpha: 1)), 23 | UserGroupMemberPresentable(name: "Frederick Vargas", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.7215686275, green: 0.9098039216, blue: 0.5607843137, alpha: 1)), 24 | UserGroupMemberPresentable(name: "Michele Owens", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.7176470588, green: 0.8784313725, blue: 0.9882352941, alpha: 1)), 25 | UserGroupMemberPresentable(name: "Freda Ramsey", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.9725490196, green: 0.937254902, blue: 0.4666666667, alpha: 1)), 26 | UserGroupMemberPresentable(name: "Anita Thomas", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.9490196078, green: 0.7568627451, blue: 0.9803921569, alpha: 1)), 27 | UserGroupMemberPresentable(name: "Leona Lane", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.9960784314, green: 0.8823529412, blue: 0.6980392157, alpha: 1)), 28 | UserGroupMemberPresentable(name: "Chad Roy", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.8784313725, green: 0.8745098039, blue: 0.9921568627, alpha: 1)), 29 | UserGroupMemberPresentable(name: "Joan Guzman", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.7215686275, green: 0.9098039216, blue: 0.5607843137, alpha: 1)), 30 | UserGroupMemberPresentable(name: "Mike Yates", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.7176470588, green: 0.8784313725, blue: 0.9882352941, alpha: 1)), 31 | UserGroupMemberPresentable(name: "Elbert Wilson", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.9725490196, green: 0.937254902, blue: 0.4666666667, alpha: 1)), 32 | UserGroupMemberPresentable(name: "Anita Thomas", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.9490196078, green: 0.7568627451, blue: 0.9803921569, alpha: 1)), 33 | UserGroupMemberPresentable(name: "Leona Lane", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.9960784314, green: 0.8823529412, blue: 0.6980392157, alpha: 1)), 34 | UserGroupMemberPresentable(name: "Chad Roy", role: "Senior iOS Engineer", avatarBackgroundColor: #colorLiteral(red: 0.8784313725, green: 0.8745098039, blue: 0.9921568627, alpha: 1)), 35 | UserGroupMemberPresentable(name: "Naida Schill", role: "Staff Engineer - Mobile DevXP", avatarBackgroundColor: #colorLiteral(red: 0.7215686275, green: 0.9098039216, blue: 0.5607843137, alpha: 1)) 36 | ] 37 | 38 | var isShortFormEnabled = true 39 | 40 | override var preferredStatusBarStyle: UIStatusBarStyle { 41 | return .lightContent 42 | } 43 | 44 | let headerView = UserGroupHeaderView() 45 | 46 | let headerPresentable = UserGroupHeaderPresentable.init(handle: "ios-engs", description: "iOS Engineers", memberCount: 10) 47 | 48 | // override func viewDidLoad() { 49 | // super.viewDidLoad() 50 | // 51 | // setupTableView() 52 | // } 53 | 54 | // MARK: - View Configurations 55 | 56 | // func setupTableView() { 57 | // 58 | // tableView.separatorStyle = .none 59 | // tableView.backgroundColor = #colorLiteral(red: 0.1019607843, green: 0.1137254902, blue: 0.1294117647, alpha: 1) 60 | // tableView.register(UserGroupMemberCell.self, forCellReuseIdentifier: "cell") 61 | // } 62 | // 63 | // // MARK: - UITableViewDataSource 64 | // 65 | // override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 66 | // return members.count 67 | // } 68 | // 69 | // override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 70 | // 71 | // guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? UserGroupMemberCell 72 | // else { return UITableViewCell() } 73 | // 74 | // cell.configure(with: members[indexPath.row]) 75 | // return cell 76 | // } 77 | // 78 | // override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 79 | // return 60.0 80 | // } 81 | // 82 | // // MARK: - UITableViewDelegate 83 | // 84 | // override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 85 | // headerView.configure(with: headerPresentable) 86 | // return headerView 87 | // } 88 | // 89 | // override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 90 | // tableView.deselectRow(at: indexPath, animated: true) 91 | // } 92 | // 93 | // // MARK: - Pan Modal Presentable 94 | // 95 | 96 | 97 | func findChildScrollView(view: UIView) -> UIScrollView? { 98 | if view.subviews.count == 0 { 99 | return nil 100 | } 101 | let fisrtChild = view.subviews[0] 102 | if fisrtChild is UIScrollView { 103 | return fisrtChild as? UIScrollView 104 | } 105 | return findChildScrollView(view: fisrtChild) 106 | } 107 | 108 | var panScrollable: UIScrollView? { 109 | 110 | return findChildScrollView(view: self.view!) 111 | } 112 | 113 | var shortFormHeight: PanModalHeight { 114 | return isShortFormEnabled ? .contentHeight(300.0) : longFormHeight 115 | } 116 | 117 | var scrollIndicatorInsets: UIEdgeInsets { 118 | let bottomOffset = presentingViewController?.bottomLayoutGuide.length ?? 0 119 | return UIEdgeInsets(top: headerView.frame.size.height, left: 0, bottom: bottomOffset, right: 0) 120 | } 121 | 122 | var anchorModalToLongForm: Bool { 123 | return false 124 | } 125 | 126 | func shouldPrioritize(panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool { 127 | let location = panModalGestureRecognizer.location(in: view) 128 | return headerView.frame.contains(location) 129 | } 130 | 131 | func willTransition(to state: PanModalPresentationController.PresentationState) { 132 | guard isShortFormEnabled, case .longForm = state 133 | else { return } 134 | 135 | isShortFormEnabled = false 136 | panModalSetNeedsLayoutUpdate() 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /ios/samplemaps/PanModal/Presentable/PanModalPresentable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PanModalPresentable.swift 3 | // PanModal 4 | // 5 | // Copyright © 2017 Tiny Speck, Inc. All rights reserved. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | 11 | /** 12 | This is the configuration object for a view controller 13 | that will be presented using the PanModal transition. 14 | 15 | Usage: 16 | ``` 17 | extension YourViewController: PanModalPresentable { 18 | func shouldRoundTopCorners: Bool { return false } 19 | } 20 | ``` 21 | */ 22 | public protocol PanModalPresentable: AnyObject { 23 | 24 | /** 25 | The scroll view embedded in the view controller. 26 | Setting this value allows for seamless transition scrolling between the embedded scroll view 27 | and the pan modal container view. 28 | */ 29 | var panScrollable: UIScrollView? { get } 30 | 31 | /** 32 | The offset between the top of the screen and the top of the pan modal container view. 33 | 34 | Default value is the topLayoutGuide.length + 21.0. 35 | */ 36 | var topOffset: CGFloat { get } 37 | 38 | /** 39 | The height of the pan modal container view 40 | when in the shortForm presentation state. 41 | 42 | This value is capped to .max, if provided value exceeds the space available. 43 | 44 | Default value is the longFormHeight. 45 | */ 46 | var shortFormHeight: PanModalHeight { get } 47 | 48 | /** 49 | The height of the pan modal container view 50 | when in the longForm presentation state. 51 | 52 | This value is capped to .max, if provided value exceeds the space available. 53 | 54 | Default value is .max. 55 | */ 56 | var longFormHeight: PanModalHeight { get } 57 | 58 | /** 59 | The corner radius used when `shouldRoundTopCorners` is enabled. 60 | 61 | Default Value is 8.0. 62 | */ 63 | var cornerRadius: CGFloat { get } 64 | 65 | /** 66 | The springDamping value used to determine the amount of 'bounce' 67 | seen when transitioning to short/long form. 68 | 69 | Default Value is 0.8. 70 | */ 71 | var springDamping: CGFloat { get } 72 | 73 | /** 74 | The transitionDuration value is used to set the speed of animation during a transition, 75 | including initial presentation. 76 | 77 | Default value is 0.5. 78 | */ 79 | var transitionDuration: Double { get } 80 | 81 | /** 82 | The animation options used when performing animations on the PanModal, utilized mostly 83 | during a transition. 84 | 85 | Default value is [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState]. 86 | */ 87 | var transitionAnimationOptions: UIView.AnimationOptions { get } 88 | 89 | /** 90 | The background view color. 91 | 92 | - Note: This is only utilized at the very start of the transition. 93 | 94 | Default Value is black with alpha component 0.7. 95 | */ 96 | var panModalBackgroundColor: UIColor { get } 97 | 98 | /** 99 | The drag indicator view color. 100 | 101 | Default value is light gray. 102 | */ 103 | var dragIndicatorBackgroundColor: UIColor { get } 104 | 105 | /** 106 | We configure the panScrollable's scrollIndicatorInsets interally so override this value 107 | to set custom insets. 108 | 109 | - Note: Use `panModalSetNeedsLayoutUpdate()` when updating insets. 110 | */ 111 | var scrollIndicatorInsets: UIEdgeInsets { get } 112 | 113 | /** 114 | A flag to determine if scrolling should be limited to the longFormHeight. 115 | Return false to cap scrolling at .max height. 116 | 117 | Default value is true. 118 | */ 119 | var anchorModalToLongForm: Bool { get } 120 | 121 | /** 122 | A flag to determine if scrolling should seamlessly transition from the pan modal container view to 123 | the embedded scroll view once the scroll limit has been reached. 124 | 125 | Default value is false. Unless a scrollView is provided and the content height exceeds the longForm height. 126 | */ 127 | var allowsExtendedPanScrolling: Bool { get } 128 | 129 | /** 130 | A flag to determine if dismissal should be initiated when swiping down on the presented view. 131 | 132 | Return false to fallback to the short form state instead of dismissing. 133 | 134 | Default value is true. 135 | */ 136 | var allowsDragToDismiss: Bool { get } 137 | 138 | /** 139 | A flag to determine if dismissal should be initiated when tapping on the dimmed background view. 140 | 141 | Default value is true. 142 | */ 143 | var allowsTapToDismiss: Bool { get } 144 | 145 | /** 146 | A flag to toggle user interactions on the container view. 147 | 148 | - Note: Return false to forward touches to the presentingViewController. 149 | 150 | Default is true. 151 | */ 152 | var isUserInteractionEnabled: Bool { get } 153 | 154 | /** 155 | A flag to determine if haptic feedback should be enabled during presentation. 156 | 157 | Default value is true. 158 | */ 159 | var isHapticFeedbackEnabled: Bool { get } 160 | 161 | /** 162 | A flag to determine if the top corners should be rounded. 163 | 164 | Default value is true. 165 | */ 166 | var shouldRoundTopCorners: Bool { get } 167 | 168 | /** 169 | A flag to determine if a drag indicator should be shown 170 | above the pan modal container view. 171 | 172 | Default value is true. 173 | */ 174 | var showDragIndicator: Bool { get } 175 | 176 | /** 177 | Asks the delegate if the pan modal should respond to the pan modal gesture recognizer. 178 | 179 | Return false to disable movement on the pan modal but maintain gestures on the presented view. 180 | 181 | Default value is true. 182 | */ 183 | func shouldRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool 184 | 185 | /** 186 | Notifies the delegate when the pan modal gesture recognizer state is either 187 | `began` or `changed`. This method gives the delegate a chance to prepare 188 | for the gesture recognizer state change. 189 | 190 | For example, when the pan modal view is about to scroll. 191 | 192 | Default value is an empty implementation. 193 | */ 194 | func willRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) 195 | 196 | /** 197 | Asks the delegate if the pan modal gesture recognizer should be prioritized. 198 | 199 | For example, you can use this to define a region 200 | where you would like to restrict where the pan gesture can start. 201 | 202 | If false, then we rely solely on the internal conditions of when a pan gesture 203 | should succeed or fail, such as, if we're actively scrolling on the scrollView. 204 | 205 | Default return value is false. 206 | */ 207 | func shouldPrioritize(panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool 208 | 209 | /** 210 | Asks the delegate if the pan modal should transition to a new state. 211 | 212 | Default value is true. 213 | */ 214 | func shouldTransition(to state: PanModalPresentationController.PresentationState) -> Bool 215 | 216 | /** 217 | Notifies the delegate that the pan modal is about to transition to a new state. 218 | 219 | Default value is an empty implementation. 220 | */ 221 | func willTransition(to state: PanModalPresentationController.PresentationState) 222 | 223 | /** 224 | Notifies the delegate that the pan modal is about to be dismissed. 225 | 226 | Default value is an empty implementation. 227 | */ 228 | func panModalWillDismiss() 229 | 230 | /** 231 | Notifies the delegate after the pan modal is dismissed. 232 | 233 | Default value is an empty implementation. 234 | */ 235 | func panModalDidDismiss() 236 | } 237 | #endif 238 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format 22 | * bundleCommand: "ram-bundle", 23 | * 24 | * // whether to bundle JS and assets in debug mode 25 | * bundleInDebug: false, 26 | * 27 | * // whether to bundle JS and assets in release mode 28 | * bundleInRelease: true, 29 | * 30 | * // whether to bundle JS and assets in another build variant (if configured). 31 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 32 | * // The configuration property can be in the following formats 33 | * // 'bundleIn${productFlavor}${buildType}' 34 | * // 'bundleIn${buildType}' 35 | * // bundleInFreeDebug: true, 36 | * // bundleInPaidRelease: true, 37 | * // bundleInBeta: true, 38 | * 39 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 40 | * // for example: to disable dev mode in the staging build type (if configured) 41 | * devDisabledInStaging: true, 42 | * // The configuration property can be in the following formats 43 | * // 'devDisabledIn${productFlavor}${buildType}' 44 | * // 'devDisabledIn${buildType}' 45 | * 46 | * // the root of your project, i.e. where "package.json" lives 47 | * root: "../../", 48 | * 49 | * // where to put the JS bundle asset in debug mode 50 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 51 | * 52 | * // where to put the JS bundle asset in release mode 53 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 54 | * 55 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 56 | * // require('./image.png')), in debug mode 57 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 58 | * 59 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 60 | * // require('./image.png')), in release mode 61 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 62 | * 63 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 64 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 65 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 66 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 67 | * // for example, you might want to remove it from here. 68 | * inputExcludes: ["android/**", "ios/**"], 69 | * 70 | * // override which node gets called and with what additional arguments 71 | * nodeExecutableAndArgs: ["node"], 72 | * 73 | * // supply additional arguments to the packager 74 | * extraPackagerArgs: [] 75 | * ] 76 | */ 77 | 78 | project.ext.react = [ 79 | entryFile: "index.js", 80 | enableHermes: false, // clean and rebuild if changing 81 | ] 82 | 83 | apply from: "../../node_modules/react-native/react.gradle" 84 | 85 | /** 86 | * Set this to true to create two separate APKs instead of one: 87 | * - An APK that only works on ARM devices 88 | * - An APK that only works on x86 devices 89 | * The advantage is the size of the APK is reduced by about 4MB. 90 | * Upload all the APKs to the Play Store and people will download 91 | * the correct one based on the CPU architecture of their device. 92 | */ 93 | def enableSeparateBuildPerCPUArchitecture = false 94 | 95 | /** 96 | * Run Proguard to shrink the Java bytecode in release builds. 97 | */ 98 | def enableProguardInReleaseBuilds = false 99 | 100 | /** 101 | * The preferred build flavor of JavaScriptCore. 102 | * 103 | * For example, to use the international variant, you can use: 104 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 105 | * 106 | * The international variant includes ICU i18n library and necessary data 107 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 108 | * give correct results when using with locales other than en-US. Note that 109 | * this variant is about 6MiB larger per architecture than default. 110 | */ 111 | def jscFlavor = 'org.webkit:android-jsc:+' 112 | 113 | /** 114 | * Whether to enable the Hermes VM. 115 | * 116 | * This should be set on project.ext.react and mirrored here. If it is not set 117 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode 118 | * and the benefits of using Hermes will therefore be sharply reduced. 119 | */ 120 | def enableHermes = project.ext.react.get("enableHermes", false); 121 | 122 | android { 123 | compileSdkVersion rootProject.ext.compileSdkVersion 124 | 125 | compileOptions { 126 | sourceCompatibility JavaVersion.VERSION_1_8 127 | targetCompatibility JavaVersion.VERSION_1_8 128 | } 129 | 130 | defaultConfig { 131 | applicationId "com.samplemaps" 132 | minSdkVersion rootProject.ext.minSdkVersion 133 | targetSdkVersion rootProject.ext.targetSdkVersion 134 | versionCode 1 135 | versionName "1.0" 136 | } 137 | splits { 138 | abi { 139 | reset() 140 | enable enableSeparateBuildPerCPUArchitecture 141 | universalApk false // If true, also generate a universal APK 142 | include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" 143 | } 144 | } 145 | signingConfigs { 146 | debug { 147 | storeFile file('debug.keystore') 148 | storePassword 'android' 149 | keyAlias 'androiddebugkey' 150 | keyPassword 'android' 151 | } 152 | } 153 | buildTypes { 154 | debug { 155 | signingConfig signingConfigs.debug 156 | } 157 | release { 158 | // Caution! In production, you need to generate your own keystore file. 159 | // see https://facebook.github.io/react-native/docs/signed-apk-android. 160 | signingConfig signingConfigs.debug 161 | minifyEnabled enableProguardInReleaseBuilds 162 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 163 | } 164 | } 165 | // applicationVariants are e.g. debug, release 166 | applicationVariants.all { variant -> 167 | variant.outputs.each { output -> 168 | // For each separate APK per architecture, set a unique version code as described here: 169 | // https://developer.android.com/studio/build/configure-apk-splits.html 170 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] 171 | def abi = output.getFilter(OutputFile.ABI) 172 | if (abi != null) { // null for the universal-debug, universal-release variants 173 | output.versionCodeOverride = 174 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 175 | } 176 | 177 | } 178 | } 179 | } 180 | 181 | dependencies { 182 | implementation fileTree(dir: "libs", include: ["*.jar"]) 183 | implementation "com.facebook.react:react-native:+" // From node_modules 184 | 185 | if (enableHermes) { 186 | def hermesPath = "../../node_modules/hermes-engine/android/"; 187 | debugImplementation files(hermesPath + "hermes-debug.aar") 188 | releaseImplementation files(hermesPath + "hermes-release.aar") 189 | } else { 190 | implementation jscFlavor 191 | } 192 | } 193 | 194 | // Run this once to be able to run the application with BUCK 195 | // puts all compile dependencies into folder libs for BUCK to use 196 | task copyDownloadableDepsToLibs(type: Copy) { 197 | from configurations.compile 198 | into 'libs' 199 | } 200 | 201 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) 202 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | * @flow 7 | */ 8 | 9 | import React from 'react'; 10 | import { 11 | Button, 12 | StyleSheet, 13 | ScrollView, 14 | View, 15 | Text, 16 | Switch, 17 | requireNativeComponent, 18 | TextInput, 19 | } from 'react-native'; 20 | 21 | import { 22 | Header, 23 | LearnMoreLinks, 24 | Colors, 25 | DebugInstructions, 26 | ReloadInstructions, 27 | } from 'react-native/Libraries/NewAppScreen'; 28 | import Modal from './Modal'; 29 | const createAppWithHeader = headerHeight => { 30 | return function App() { 31 | return ( 32 | 33 | {/* {/**/} 38 | 39 |
40 | {global.HermesInternal == null ? null : ( 41 | 42 | Engine: Hermes 43 | 44 | )} 45 | 46 | 47 | Step One 48 | 49 | Edit App.js to change this 50 | screen and then come back to see your edits. 51 | 52 | 53 | 54 | See Your Changes 55 | 56 | 57 | 58 | 59 | 60 | Debug 61 | 62 | 63 | 64 | 65 | 66 | Learn More 67 | 68 | Read the docs to discover what to do next: 69 | 70 | 71 | 72 | 73 | 74 | 75 | ); 76 | }; 77 | }; 78 | 79 | const SomeApp = createAppWithHeader(20); 80 | 81 | export default function ConfigScreen() { 82 | const [topOffset, setTopOffset] = React.useState(42); 83 | const [isShortFormEnabled, setIsShortFormEnabled] = React.useState(true); 84 | const [longFormHeight, setLongFormHeight] = React.useState(null); 85 | const [cornerRadius, setCornerRadius] = React.useState(8); 86 | const [springDamping, setSpringDamping] = React.useState(0.8); 87 | const [transitionDuration, setTransitionDuration] = React.useState(0.5); 88 | const [anchorModalToLongForm, setAnchorModalToLongForm] = React.useState( 89 | true, 90 | ); 91 | const [allowsDragToDismiss, setAllowsDragToDismiss] = React.useState(true); 92 | const [allowsTapToDismiss, setAllowsTapToDismiss] = React.useState(true); 93 | const [ 94 | isUserInteractionEnabled, 95 | setIsUserInteractionEnabled, 96 | ] = React.useState(true); 97 | const [isHapticFeedbackEnabled, setIsHapticFeedbackEnabled] = React.useState( 98 | true, 99 | ); 100 | const [shouldRoundTopCorners, setShouldRoundTopCorners] = React.useState( 101 | true, 102 | ); 103 | const [showDragIndicator, setShowDragIndicator] = React.useState(true); 104 | const [headerHeight, setHeaderHeight] = React.useState(50); 105 | const [shortFormHeight, setShortFormHeight] = React.useState(500); 106 | const [startFromShortForm, setStartFromShortForm] = React.useState(false); 107 | const [visible, setVisible] = React.useState(false); 108 | 109 | return ( 110 | 111 |