Skip to content

Commit

Permalink
⭐️ Impl: Prop - ModalView.sheetDetents
Browse files Browse the repository at this point in the history
Related:
* `TODO:2023-04-20-23-58-24` - Impl. sheets + detents.
* `TODO:2023-04-21-00-43-59` - Impl. prop `sheetDetents`.

Summary:
* Native - Impl. prop `RNIModalView.modalSheetDetents`.
* Native - Impl. logic for parsing system defined detents (i.e. `UISheetPresentationController+Init`).
* Native - Impl. logic for parsing custom detents (i.e. `RNIModalCustomSheetDetent`).
* Types - Add types that maps to `UISheetPresentationController.Detents` (i.e. `TUISheetPresentationControllerDetents`).
* Types - Add types that maps to `RNIModalCustomSheetDetent`.
* Impl: Prop - `ModalView.modalSheetDetents`.
  • Loading branch information
dominicstop committed Apr 20, 2023
1 parent d117b26 commit 5eab7db
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// UISheetPresentationController+Init.swift
// react-native-ios-modal
//
// Created by Dominic Go on 4/21/23.
//

import Foundation


@available(iOS 15.0, *)
extension UISheetPresentationController.Detent {
static func fromString(_ string: String) -> UISheetPresentationController.Detent? {
switch string {
case "medium": return .medium();
case "large" : return .large();

default: return nil;
};
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//
// RNIModalCustomSheetDetent.swift
// react-native-ios-modal
//
// Created by Dominic Go on 4/21/23.
//

import Foundation

enum RNIModalCustomSheetDetentMode {

case relative(value: Double);
case constant(value: Double);

var rawValueString: String {
switch self {
case .constant: return "constant";
case .relative: return "relative";
};
};
};

struct RNIModalCustomSheetDetent {

typealias OnDetentDidCreate = (
_ containerTraitCollection: UITraitCollection,
_ maximumDetentValue: CGFloat
) -> Void;

let mode: RNIModalCustomSheetDetentMode;
let key: String;

let onDetentDidCreate: OnDetentDidCreate?;

init?(
forDict dict: Dictionary<String, Any>,
onDetentDidCreate: OnDetentDidCreate? = nil
) {
guard let rawMode = dict["mode"] as? String,
let rawKey = dict["key"] as? String
else { return nil };

self.key = rawKey;
self.onDetentDidCreate = onDetentDidCreate;

let mode: RNIModalCustomSheetDetentMode? = {
switch rawMode {
case "relative":
guard let rawValue = dict["sizeMultiplier"] as? NSNumber
else { return nil };

return .relative(value: rawValue.doubleValue);

case "constant":
guard let rawValue = dict["sizeConstant"] as? NSNumber
else { return nil };

return .constant(value: rawValue.doubleValue);

default:
return nil;
};
}();

guard let mode = mode else { return nil };
self.mode = mode;
};

@available(iOS 15.0, *)
var synthesizedDetentIdentifier:
UISheetPresentationController.Detent.Identifier {

UISheetPresentationController.Detent.Identifier(self.key);
};

@available(iOS 16.0, *)
var synthesizedDetent: UISheetPresentationController.Detent {
return .custom(identifier: self.synthesizedDetentIdentifier) {
self.onDetentDidCreate?(
$0.containerTraitCollection,
$0.maximumDetentValue
);

switch self.mode {
case let .relative(value):
return value * $0.maximumDetentValue;

case let .constant(value):
return value;
};
}
};
};
51 changes: 51 additions & 0 deletions ios/src_library/React Native/RNIModalView/RNIModalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ public class RNIModalView:
}
};


@objc var modalSheetDetents: NSArray?;

// MARK: - Properties: Synthesized From Props
// ------------------------------------------

Expand Down Expand Up @@ -255,6 +258,22 @@ public class RNIModalView:
return blurStyle;
};

@available(iOS 15.0, *)
public var synthesizedModalSheetDetents: [UISheetPresentationController.Detent]? {
self.modalSheetDetents?.compactMap {
if let string = $0 as? String {
return UISheetPresentationController.Detent.fromString(string);

} else if #available(iOS 16.0, *),
let dict = $0 as? Dictionary<String, Any> {
let customDetent = RNIModalCustomSheetDetent(forDict: dict)
return customDetent?.synthesizedDetent;
};

return nil;
};
};

// MARK: - Properties: Synthesized
// -------------------------------

Expand All @@ -266,6 +285,28 @@ public class RNIModalView:
);
};

// MARK: - Properties: Computed
// ----------------------------

@available(iOS 15.0, *)
var sheetPresentationController: UISheetPresentationController? {
guard let presentedVC = self.modalViewController else { return nil };

switch presentedVC.modalPresentationStyle {
case .popover:
return presentedVC.popoverPresentationController?
.adaptiveSheetPresentationController;

case .automatic,
.formSheet,
.pageSheet:
return presentedVC.sheetPresentationController;

default:
return nil;
};
};

// MARK: - Init
// ------------

Expand Down Expand Up @@ -475,6 +516,16 @@ public class RNIModalView:

modalVC.modalTransitionStyle = self.synthesizedModalTransitionStyle;
modalVC.modalPresentationStyle = self.synthesizedModalPresentationStyle;

if #available(iOS 15.0, *),
let sheetController = self.sheetPresentationController {

if let detents = self.synthesizedModalSheetDetents,
detents.count >= 1 {

sheetController.detents = detents;
};
};

#if DEBUG
print(
Expand Down
14 changes: 7 additions & 7 deletions ios/src_library/React Native/RNIModalView/RNIModalViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@

@interface RCT_EXTERN_MODULE(RNIModalViewManager, RCTViewManager)

// ------------------------------
// MARK: Props - Callbacks/Events
// ------------------------------
// MARK: - Props - Callbacks/Events
// --------------------------------

RCT_EXPORT_VIEW_PROPERTY(onModalWillPresent, RCTBubblingEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onModalDidPresent, RCTBubblingEventBlock);
Expand All @@ -29,9 +28,9 @@ @interface RCT_EXTERN_MODULE(RNIModalViewManager, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(onPresentationControllerDidDismiss, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPresentationControllerDidAttemptToDismiss, RCTBubblingEventBlock);

// --------------------------------
// MARK: Props - RN Component Props
// --------------------------------

// MARK: - Props - RN Component Props
// ----------------------------------

RCT_EXPORT_VIEW_PROPERTY(presentViaMount , BOOL);
RCT_EXPORT_VIEW_PROPERTY(isModalBGBlurred , BOOL);
Expand All @@ -41,11 +40,12 @@ @interface RCT_EXTERN_MODULE(RNIModalViewManager, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(isModalInPresentation , BOOL);
RCT_EXPORT_VIEW_PROPERTY(allowModalForceDismiss, BOOL);


RCT_EXPORT_VIEW_PROPERTY(modalID , NSString);
RCT_EXPORT_VIEW_PROPERTY(modalTransitionStyle , NSString);
RCT_EXPORT_VIEW_PROPERTY(modalBGBlurEffectStyle, NSString);
RCT_EXPORT_VIEW_PROPERTY(modalPresentationStyle, NSString);

RCT_EXPORT_VIEW_PROPERTY(modalSheetDetents, NSArray);

@end

4 changes: 4 additions & 0 deletions src/components/ModalView/ModalView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ export class ModalView extends
modalBGBlurEffectStyle,
modalPresentationStyle,

// native props - objects/arrays
modalSheetDetents,

// native props - events
onModalWillPresent,
onModalDidPresent,
Expand Down Expand Up @@ -195,6 +198,7 @@ export class ModalView extends
onPresentationControllerDidDismiss,
onPresentationControllerDidAttemptToDismiss,
containerStyle,
modalSheetDetents,

// C - View-Related Props
children,
Expand Down
3 changes: 3 additions & 0 deletions src/components/ModalView/ModalViewTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export type ModalViewBaseProps = Partial<
| 'modalBGBlurEffectStyle'
| 'modalPresentationStyle'

// props - object/arrays
| 'modalSheetDetents'

// props - events
| 'onModalWillPresent'
| 'onModalDidPresent'
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './native_modules/RNIModalViewModule';
export * from './types/UIModalTypes';
export * from './types/UIBlurEffectStyles';
export * from './types/RNIModalViewRelatedTypes';
export * from './types/RNIModalTypes';
12 changes: 10 additions & 2 deletions src/native_components/RNIModalView/RNIModalViewTypes.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type { ViewProps } from 'react-native';

import type { TUIBlurEffectStyles } from 'src/types/UIBlurEffectStyles';

import type {
TUIModalPresentationStyle,
TUIModalTransitionStyle,
TUISheetPresentationControllerDetents,
} from 'src/types/UIModalTypes';

import type { TUIBlurEffectStyles } from 'src/types/UIBlurEffectStyles';
import type { RNIModalCustomSheetDetent } from 'src/types/RNIModalTypes';
import type { ViewManagerConstantMap } from 'src/types/ViewModuleRelatedTypes';

import type {
Expand Down Expand Up @@ -47,6 +48,13 @@ export type RNIModalViewBaseProps = {
modalBGBlurEffectStyle?: TUIBlurEffectStyles;
modalPresentationStyle?: TUIModalPresentationStyle;

// Props - Objects/Arrays
// ----------------------

modalSheetDetents?: Array<
TUISheetPresentationControllerDetents | RNIModalCustomSheetDetent
>;

// Props - Events
// --------------

Expand Down
12 changes: 12 additions & 0 deletions src/types/RNIModalTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// prettier-ignore

/** Maps to `RNIModalCustomSheetDetent` */
export type RNIModalCustomSheetDetent = {
mode: 'relative';
key: string;
sizeMultiplier: number;
} | {
mode: 'constant';
key: string;
sizeConstant: number;
};
3 changes: 3 additions & 0 deletions src/types/UIModalTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ export type TUIModalPresentationStyle =
| 'overCurrentContext'
| 'popover'
| 'blurOverFullScreen';

/** Maps to `UISheetPresentationController.Detents` */
export type TUISheetPresentationControllerDetents = 'medium' | 'large';

0 comments on commit 5eab7db

Please sign in to comment.