From 27cf1b12f2e0b42b2c0e36abe96d3db435bdd1b0 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2020 04:50:10 +0000
Subject: [PATCH 1/6] Bump json from 2.2.0 to 2.3.1

Bumps [json](https://github.com/flori/json) from 2.2.0 to 2.3.1.
- [Release notes](https://github.com/flori/json/releases)
- [Changelog](https://github.com/flori/json/blob/master/CHANGES.md)
- [Commits](https://github.com/flori/json/compare/v2.2.0...v2.3.1)

Signed-off-by: dependabot[bot] <support@github.com>
---
 Gemfile.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index bcfcc7b..3d5242a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -56,7 +56,7 @@ GEM
     httpclient (2.8.3)
     i18n (0.9.5)
       concurrent-ruby (~> 1.0)
-    json (2.2.0)
+    json (2.3.1)
     minitest (5.12.2)
     molinillo (0.6.6)
     nanaimo (0.2.6)

From 6fae58cbb2a8f4ca9442be11d60f0d119cd8b2e3 Mon Sep 17 00:00:00 2001
From: Chip <chip.snyder@automattic.com>
Date: Tue, 15 Dec 2020 11:49:32 -0500
Subject: [PATCH 2/6] Add keyboard notification animation helper (#79)

* Cut 1.7.4

* Add Keyboard animation helper for animating along side keyboard changes

* Bump podspec version

* Add demo view controller for keybaord animation helper

* Add explicit Value types

Co-authored-by: Jeremy Massel <jeremy.massel@automattic.com>
---
 Example/Example.xcodeproj/project.pbxproj     |  4 +
 Example/Example/Base.lproj/Main.storyboard    | 96 ++++++++++++++++---
 ...boardAnimationsExampleViewController.swift | 63 ++++++++++++
 Example/Example/ViewController.swift          |  5 +
 WordPressUI.podspec                           |  2 +-
 .../Extensions/UIView+Animations.swift        | 20 +++-
 6 files changed, 174 insertions(+), 16 deletions(-)
 create mode 100644 Example/Example/KeyboardAnimationsExampleViewController.swift

diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj
index bff6821..d2ffb68 100644
--- a/Example/Example.xcodeproj/project.pbxproj
+++ b/Example/Example.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		46B30DCD2583F63100A25E66 /* KeyboardAnimationsExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46B30DCC2583F63100A25E66 /* KeyboardAnimationsExampleViewController.swift */; };
 		F1C4EBE5218A37D700B8A9F7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1C4EBE4218A37D700B8A9F7 /* AppDelegate.swift */; };
 		F1C4EBE7218A37D700B8A9F7 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1C4EBE6218A37D700B8A9F7 /* ViewController.swift */; };
 		F1C4EBEA218A37D700B8A9F7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F1C4EBE8218A37D700B8A9F7 /* Main.storyboard */; };
@@ -70,6 +71,7 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		46B30DCC2583F63100A25E66 /* KeyboardAnimationsExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardAnimationsExampleViewController.swift; sourceTree = "<group>"; };
 		F1C4EBE1218A37D700B8A9F7 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		F1C4EBE4218A37D700B8A9F7 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
 		F1C4EBE6218A37D700B8A9F7 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
@@ -139,6 +141,7 @@
 			children = (
 				F1C4EBE4218A37D700B8A9F7 /* AppDelegate.swift */,
 				F1C4EBE6218A37D700B8A9F7 /* ViewController.swift */,
+				46B30DCC2583F63100A25E66 /* KeyboardAnimationsExampleViewController.swift */,
 				F1C4EBE8218A37D700B8A9F7 /* Main.storyboard */,
 				F1C4EBEB218A37D800B8A9F7 /* Assets.xcassets */,
 				F1C4EBED218A37D800B8A9F7 /* LaunchScreen.storyboard */,
@@ -346,6 +349,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				F1C4EBE7218A37D700B8A9F7 /* ViewController.swift in Sources */,
+				46B30DCD2583F63100A25E66 /* KeyboardAnimationsExampleViewController.swift in Sources */,
 				F1C4EBE5218A37D700B8A9F7 /* AppDelegate.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
diff --git a/Example/Example/Base.lproj/Main.storyboard b/Example/Example/Base.lproj/Main.storyboard
index 6b74573..1e16679 100644
--- a/Example/Example/Base.lproj/Main.storyboard
+++ b/Example/Example/Base.lproj/Main.storyboard
@@ -1,10 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PbN-Bb-478">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PbN-Bb-478">
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17126"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
@@ -34,6 +35,7 @@
                     <navigationItem key="navigationItem" title="Root View Controller" id="ua7-K6-ibe"/>
                     <connections>
                         <segue destination="sFZ-hP-s6g" kind="show" identifier="FancyButtonsSegue" id="avn-Um-QAq"/>
+                        <segue destination="3m8-q6-5bU" kind="show" identifier="KeyboardAnimationsSegue" id="5OM-6x-B3U"/>
                     </connections>
                 </tableViewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="ePj-1F-MpD" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -49,59 +51,59 @@
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="40" translatesAutoresizingMaskIntoConstraints="NO" id="4IX-T0-GRU">
-                                <rect key="frame" x="96.5" y="79.5" width="182" height="552"/>
+                                <rect key="frame" x="97" y="79.5" width="181" height="552"/>
                                 <subviews>
                                     <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DLq-Jr-68H" customClass="FancyButton" customModule="WordPressUI">
-                                        <rect key="frame" x="0.0" y="0.0" width="182" height="34"/>
+                                        <rect key="frame" x="0.0" y="0.0" width="181" height="34"/>
                                         <state key="normal" title="Primary enabled"/>
                                         <userDefinedRuntimeAttributes>
                                             <userDefinedRuntimeAttribute type="boolean" keyPath="isPrimary" value="YES"/>
                                         </userDefinedRuntimeAttributes>
                                     </button>
                                     <button opaque="NO" contentMode="scaleToFill" selected="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="99W-Sf-T4r" customClass="FancyButton" customModule="WordPressUI">
-                                        <rect key="frame" x="0.0" y="74" width="182" height="34"/>
+                                        <rect key="frame" x="0.0" y="74" width="181" height="34"/>
                                         <state key="normal" title="Primary selected"/>
                                         <userDefinedRuntimeAttributes>
                                             <userDefinedRuntimeAttribute type="boolean" keyPath="isPrimary" value="YES"/>
                                         </userDefinedRuntimeAttributes>
                                     </button>
                                     <button opaque="NO" contentMode="scaleToFill" highlighted="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="V1C-qw-HGz" customClass="FancyButton" customModule="WordPressUI">
-                                        <rect key="frame" x="0.0" y="148" width="182" height="34"/>
+                                        <rect key="frame" x="0.0" y="148" width="181" height="34"/>
                                         <state key="normal" title="Primary highlighted"/>
                                         <userDefinedRuntimeAttributes>
                                             <userDefinedRuntimeAttribute type="boolean" keyPath="isPrimary" value="YES"/>
                                         </userDefinedRuntimeAttributes>
                                     </button>
                                     <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rse-9O-SFu" customClass="FancyButton" customModule="WordPressUI">
-                                        <rect key="frame" x="0.0" y="222" width="182" height="34"/>
+                                        <rect key="frame" x="0.0" y="222" width="181" height="34"/>
                                         <state key="normal" title="Primary disabled"/>
                                         <userDefinedRuntimeAttributes>
                                             <userDefinedRuntimeAttribute type="boolean" keyPath="isPrimary" value="YES"/>
                                         </userDefinedRuntimeAttributes>
                                     </button>
                                     <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UAb-pT-sYQ" customClass="FancyButton" customModule="WordPressUI">
-                                        <rect key="frame" x="0.0" y="296" width="182" height="34"/>
+                                        <rect key="frame" x="0.0" y="296" width="181" height="34"/>
                                         <state key="normal" title="Secondary enabled"/>
                                         <userDefinedRuntimeAttributes>
                                             <userDefinedRuntimeAttribute type="boolean" keyPath="isPrimary" value="NO"/>
                                         </userDefinedRuntimeAttributes>
                                     </button>
                                     <button opaque="NO" contentMode="scaleToFill" selected="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="raJ-LB-lIj" customClass="FancyButton" customModule="WordPressUI">
-                                        <rect key="frame" x="0.0" y="370" width="182" height="34"/>
+                                        <rect key="frame" x="0.0" y="370" width="181" height="34"/>
                                         <state key="normal" title="Secondary selected"/>
                                         <userDefinedRuntimeAttributes>
                                             <userDefinedRuntimeAttribute type="boolean" keyPath="isPrimary" value="NO"/>
                                         </userDefinedRuntimeAttributes>
                                     </button>
                                     <button opaque="NO" contentMode="scaleToFill" highlighted="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Cb-gy-BQF" customClass="FancyButton" customModule="WordPressUI">
-                                        <rect key="frame" x="0.0" y="444" width="182" height="34"/>
+                                        <rect key="frame" x="0.0" y="444" width="181" height="34"/>
                                         <state key="normal" title="Secondary highlighted"/>
                                         <userDefinedRuntimeAttributes>
                                             <userDefinedRuntimeAttribute type="boolean" keyPath="isPrimary" value="NO"/>
                                         </userDefinedRuntimeAttributes>
                                     </button>
                                     <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jbE-un-BvP" customClass="FancyButton" customModule="WordPressUI">
-                                        <rect key="frame" x="0.0" y="518" width="182" height="34"/>
+                                        <rect key="frame" x="0.0" y="518" width="181" height="34"/>
                                         <state key="normal" title="Secondary disabled"/>
                                         <userDefinedRuntimeAttributes>
                                             <userDefinedRuntimeAttribute type="boolean" keyPath="isPrimary" value="YES"/>
@@ -110,12 +112,12 @@
                                 </subviews>
                             </stackView>
                         </subviews>
-                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                        <viewLayoutGuide key="safeArea" id="O2a-cZ-0ji"/>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <constraints>
                             <constraint firstItem="4IX-T0-GRU" firstAttribute="centerX" secondItem="O2a-cZ-0ji" secondAttribute="centerX" id="cF8-1m-2mC"/>
                             <constraint firstItem="4IX-T0-GRU" firstAttribute="centerY" secondItem="O2a-cZ-0ji" secondAttribute="centerY" id="mrV-bV-4yf"/>
                         </constraints>
-                        <viewLayoutGuide key="safeArea" id="O2a-cZ-0ji"/>
                     </view>
                     <navigationItem key="navigationItem" id="QQQ-hf-TLL"/>
                 </viewController>
@@ -139,5 +141,73 @@
             </objects>
             <point key="canvasLocation" x="-385" y="-244"/>
         </scene>
+        <!--Keyboard Animations Example View Controller-->
+        <scene sceneID="UfJ-pv-GgC">
+            <objects>
+                <viewController id="3m8-q6-5bU" customClass="KeyboardAnimationsExampleViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="uT8-tJ-oqm">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Tap here to open keyboard" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="X2k-Nt-hCp">
+                                <rect key="frame" x="16" y="64" width="343" height="34"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <textInputTraits key="textInputTraits" autocorrectionType="yes"/>
+                            </textField>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mDX-xF-zCr">
+                                <rect key="frame" x="179" y="615" width="176" height="32"/>
+                                <color key="backgroundColor" systemColor="systemBlueColor"/>
+                                <inset key="contentEdgeInsets" minX="20" minY="5" maxX="20" maxY="5"/>
+                                <state key="normal" title="Toggle Keyboard">
+                                    <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                </state>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                        <integer key="value" value="15"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                                <connections>
+                                    <action selector="didTapButton:" destination="3m8-q6-5bU" eventType="touchUpInside" id="NyL-xt-8sS"/>
+                                </connections>
+                            </button>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tapping in the text box should animate the button below so that it is always above the keyboard." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QNw-4D-Eed">
+                                <rect key="frame" x="16" y="113" width="343" height="61"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <nil key="textColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                        </subviews>
+                        <viewLayoutGuide key="safeArea" id="Bkc-dm-Xs7"/>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                        <constraints>
+                            <constraint firstItem="Bkc-dm-Xs7" firstAttribute="trailing" secondItem="X2k-Nt-hCp" secondAttribute="trailing" constant="16" id="ApP-NI-m7w"/>
+                            <constraint firstItem="QNw-4D-Eed" firstAttribute="trailing" secondItem="X2k-Nt-hCp" secondAttribute="trailing" id="FUF-g1-dPe"/>
+                            <constraint firstItem="Bkc-dm-Xs7" firstAttribute="bottom" secondItem="mDX-xF-zCr" secondAttribute="bottom" constant="20" id="OcG-gK-VkP"/>
+                            <constraint firstItem="X2k-Nt-hCp" firstAttribute="leading" secondItem="Bkc-dm-Xs7" secondAttribute="leading" constant="16" id="TzF-42-Fp4"/>
+                            <constraint firstItem="mDX-xF-zCr" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Bkc-dm-Xs7" secondAttribute="leading" constant="20" id="VvH-uI-USN"/>
+                            <constraint firstItem="QNw-4D-Eed" firstAttribute="top" secondItem="X2k-Nt-hCp" secondAttribute="bottom" constant="15" id="ce1-7o-5Ha"/>
+                            <constraint firstItem="QNw-4D-Eed" firstAttribute="leading" secondItem="X2k-Nt-hCp" secondAttribute="leading" id="l4J-BD-OsV"/>
+                            <constraint firstItem="X2k-Nt-hCp" firstAttribute="top" secondItem="Bkc-dm-Xs7" secondAttribute="top" constant="20" id="ruU-dE-ACz"/>
+                            <constraint firstItem="Bkc-dm-Xs7" firstAttribute="trailing" secondItem="mDX-xF-zCr" secondAttribute="trailing" constant="20" id="un4-ys-yHq"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" id="NCF-t9-dFX"/>
+                    <connections>
+                        <outlet property="bottomConstraintForAnimation" destination="OcG-gK-VkP" id="QxE-Bt-iDj"/>
+                        <outlet property="textView" destination="X2k-Nt-hCp" id="vEd-Y9-1df"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="bAl-pf-sw6" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="565.60000000000002" y="1110.4947526236883"/>
+        </scene>
     </scenes>
+    <resources>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+        <systemColor name="systemBlueColor">
+            <color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+    </resources>
 </document>
diff --git a/Example/Example/KeyboardAnimationsExampleViewController.swift b/Example/Example/KeyboardAnimationsExampleViewController.swift
new file mode 100644
index 0000000..6d1b00f
--- /dev/null
+++ b/Example/Example/KeyboardAnimationsExampleViewController.swift
@@ -0,0 +1,63 @@
+import UIKit
+
+class KeyboardAnimationsExampleViewController: UIViewController {
+    @IBOutlet weak var textView: UITextField!
+    @IBOutlet weak var bottomConstraintForAnimation: NSLayoutConstraint!
+    private var notificationObservers: [NSObjectProtocol] = []
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        startObservingKeyboardChanges()
+    }
+
+    deinit {
+        stopObservingKeyboardChanges()
+    }
+
+    @IBAction func didTapButton(_ sender: Any) {
+        if textView.isFirstResponder {
+            textView.resignFirstResponder()
+        } else {
+            textView.becomeFirstResponder()
+        }
+    }
+
+    private func keybaordDidOpen(_ endFrame: CGRect) {
+        bottomConstraintForAnimation.constant = endFrame.height - self.view.safeAreaInsets.bottom + 10
+        view.setNeedsLayout()
+        view.layoutIfNeeded()
+    }
+
+    func startObservingKeyboardChanges() {
+        let willShowObserver = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { (notification) in
+            UIView.animate(withKeyboard: notification) { (_, endFrame) in
+                self.keybaordDidOpen(endFrame)
+            }
+        }
+
+        let willHideObserver = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { (notification) in
+            UIView.animate(withKeyboard: notification) { (beginFrame, endFrame) in
+                self.bottomConstraintForAnimation.constant = 20
+                self.view.setNeedsLayout()
+                self.view.layoutIfNeeded()
+            }
+        }
+
+        let willChangeFrameObserver = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification, object: nil, queue: .main) { (notification) in
+            UIView.animate(withKeyboard: notification) { (_, endFrame) in
+                self.keybaordDidOpen(endFrame)
+            }
+        }
+
+        notificationObservers.append(willShowObserver)
+        notificationObservers.append(willHideObserver)
+        notificationObservers.append(willChangeFrameObserver)
+    }
+
+    private func stopObservingKeyboardChanges() {
+        notificationObservers.forEach { (observer) in
+            NotificationCenter.default.removeObserver(observer)
+        }
+        notificationObservers = []
+    }
+}
diff --git a/Example/Example/ViewController.swift b/Example/Example/ViewController.swift
index eaf181b..44ccfc4 100644
--- a/Example/Example/ViewController.swift
+++ b/Example/Example/ViewController.swift
@@ -33,6 +33,11 @@ class ViewController: UITableViewController
                     self.showFancyButtons()
                 })
             ]),
+            DemoSection(title: "Keyboard Animations", rows: [
+                DemoRow(title: "Keyboard Animations", action: {
+                    self.performSegue(withIdentifier: "KeyboardAnimationsSegue", sender: self)
+                })
+            ])
         ]
     }
     
diff --git a/WordPressUI.podspec b/WordPressUI.podspec
index f7b1412..ff33b2d 100644
--- a/WordPressUI.podspec
+++ b/WordPressUI.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name          = "WordPressUI"
-  s.version       = "1.8.0"
+  s.version       = "1.9.0-beta.1"
   s.summary       = "Home of reusable WordPress UI components."
 
   s.description   = <<-DESC
diff --git a/WordPressUI/Extensions/UIView+Animations.swift b/WordPressUI/Extensions/UIView+Animations.swift
index 9587a63..366f277 100644
--- a/WordPressUI/Extensions/UIView+Animations.swift
+++ b/WordPressUI/Extensions/UIView+Animations.swift
@@ -1,5 +1,4 @@
-import Foundation
-
+import UIKit
 
 // MARK: UIView Animation Helpers
 //
@@ -153,6 +152,23 @@ extension UIView {
         }
     }
 
+    /// Coordinates an animation block alongside a keyboard's notification animation event.
+    /// - Parameters:
+    ///     - notification: A notficiation from a keyboard change event (keyboardWillShowNotification, keyboardWillHideNotification, etc)
+    ///     - animations: The animation block to be preformed. The block will provide the rects from keyboardFrameBeginUserInfoKey and keyboardFrameEndUserInfoKey to the animation block.
+    ///
+    public static func animate(withKeyboard notification: Notification, _ animations: @escaping (CGRect, CGRect) -> Void ) {
+        guard let userInfo = notification.userInfo else { return }
+        let duration: TimeInterval = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval ?? 0
+        let beginFrame: CGRect = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect.zero
+        let endFrame: CGRect = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect.zero
+        let animationCurve: AnimationOptions = AnimationOptions(rawValue: (userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt ?? 0))
+
+        UIView.animate(withDuration: duration, delay: 0, options: animationCurve, animations: {
+            animations(beginFrame, endFrame)
+        }, completion: nil)
+    }
+       
     /// Private Constants
     ///
     private struct Animations {

From c0fc0ea3585ced77c477eec384fbb134a4637ad2 Mon Sep 17 00:00:00 2001
From: Emily Laguna <emily.laguna@automattic.com>
Date: Mon, 21 Dec 2020 15:00:05 -0500
Subject: [PATCH 3/6] Check if the child view controller is presenting a view

---
 WordPressUI/BottomSheet/BottomSheetViewController.swift | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/WordPressUI/BottomSheet/BottomSheetViewController.swift b/WordPressUI/BottomSheet/BottomSheetViewController.swift
index a8814a1..2b9b97d 100644
--- a/WordPressUI/BottomSheet/BottomSheetViewController.swift
+++ b/WordPressUI/BottomSheet/BottomSheetViewController.swift
@@ -167,10 +167,18 @@ public class BottomSheetViewController: UIViewController {
     }
 
     @objc func keyboardWillShow(_ notification: NSNotification) {
+        guard childViewController?.presentedViewController == nil else {
+            return
+        }
+
         self.presentedVC?.transition(to: .expanded)
     }
 
     @objc func keyboardWillHide(_ notification: NSNotification) {
+        guard childViewController?.presentedViewController == nil else {
+            return
+        }
+
         self.presentedVC?.transition(to: .collapsed)
     }
 }

From 99024b1f9d06802aeb528cc9f0d4e0a743c8052f Mon Sep 17 00:00:00 2001
From: Emily Laguna <emily.laguna@automattic.com>
Date: Mon, 21 Dec 2020 15:05:57 -0500
Subject: [PATCH 4/6] Prevent a possible crash when going back while
 transitioning

---
 WordPressUI/BottomSheet/DrawerPresentationController.swift | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/WordPressUI/BottomSheet/DrawerPresentationController.swift b/WordPressUI/BottomSheet/DrawerPresentationController.swift
index 930b6b2..83bef21 100644
--- a/WordPressUI/BottomSheet/DrawerPresentationController.swift
+++ b/WordPressUI/BottomSheet/DrawerPresentationController.swift
@@ -484,7 +484,7 @@ private extension DrawerPresentationController {
             /// Halts scrolling when scrolling down from expanded or up from compact
             haltScrolling(scrollView)
 
-        } else if scrollView.isScrolling || isPresentedViewAnimating {
+        } else if scrollView.isScrolling {
 
             if isPresentedViewAnchored {
                 /// Allow normal scrolling (with tracking)

From 2aca2d62d61ac910e0375105a884aa0df271bead Mon Sep 17 00:00:00 2001
From: Emily Laguna <emily.laguna@automattic.com>
Date: Mon, 21 Dec 2020 15:47:27 -0500
Subject: [PATCH 5/6] Bump to 1.9.0-beta.2

---
 WordPressUI.podspec | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/WordPressUI.podspec b/WordPressUI.podspec
index ff33b2d..5821d31 100644
--- a/WordPressUI.podspec
+++ b/WordPressUI.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name          = "WordPressUI"
-  s.version       = "1.9.0-beta.1"
+  s.version       = "1.9.0-beta.2"
   s.summary       = "Home of reusable WordPress UI components."
 
   s.description   = <<-DESC

From fd6f923035c655bd5c0214997b7cc08902f326e9 Mon Sep 17 00:00:00 2001
From: Jeremy Massel <jeremy.massel@automattic.com>
Date: Mon, 11 Jan 2021 11:57:14 -0700
Subject: [PATCH 6/6] Cut 1.9.0

---
 WordPressUI.podspec | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/WordPressUI.podspec b/WordPressUI.podspec
index 5821d31..452ade4 100644
--- a/WordPressUI.podspec
+++ b/WordPressUI.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name          = "WordPressUI"
-  s.version       = "1.9.0-beta.2"
+  s.version       = "1.9.0"
   s.summary       = "Home of reusable WordPress UI components."
 
   s.description   = <<-DESC