react-native-nitro-modal 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/NitroModal.podspec +29 -0
- package/README.md +39 -0
- package/android/CMakeLists.txt +24 -0
- package/android/build.gradle +124 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +11 -0
- package/android/src/main/java/com/margelo/nitro/nitromodal/BottomSheetPresenter.kt +284 -0
- package/android/src/main/java/com/margelo/nitro/nitromodal/HybridNitroModal.kt +312 -0
- package/android/src/main/java/com/margelo/nitro/nitromodal/ModalConfig.kt +50 -0
- package/android/src/main/java/com/margelo/nitro/nitromodal/ModalContentRoot.kt +115 -0
- package/android/src/main/java/com/margelo/nitro/nitromodal/ModalPresenter.kt +253 -0
- package/android/src/main/java/com/margelo/nitro/nitromodal/NitroModalHostView.kt +52 -0
- package/android/src/main/java/com/margelo/nitro/nitromodal/NitroModalPackage.kt +28 -0
- package/android/src/main/java/com/margelo/nitro/nitromodal/NitroModalViewManager.kt +67 -0
- package/android/src/main/java/com/margelo/nitro/nitromodal/PopupPresenter.kt +156 -0
- package/android/src/main/res/values/styles.xml +17 -0
- package/ios/BackdropView.swift +64 -0
- package/ios/HybridNitroModal.swift +329 -0
- package/ios/HybridNitroModalComponent+Children.mm +77 -0
- package/ios/ModalConfig.swift +73 -0
- package/ios/NitroModalHostView.swift +91 -0
- package/ios/PopupViewController.swift +223 -0
- package/ios/SheetViewController.swift +244 -0
- package/lib/module/NitroModal.js +188 -0
- package/lib/module/NitroModal.js.map +1 -0
- package/lib/module/NitroModal.nitro.js +4 -0
- package/lib/module/NitroModal.nitro.js.map +1 -0
- package/lib/module/NitroModalView.js +17 -0
- package/lib/module/NitroModalView.js.map +1 -0
- package/lib/module/NitroModalView.native.js +6 -0
- package/lib/module/NitroModalView.native.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NitroModal.d.ts +59 -0
- package/lib/typescript/src/NitroModal.d.ts.map +1 -0
- package/lib/typescript/src/NitroModal.nitro.d.ts +78 -0
- package/lib/typescript/src/NitroModal.nitro.d.ts.map +1 -0
- package/lib/typescript/src/NitroModalView.d.ts +4 -0
- package/lib/typescript/src/NitroModalView.d.ts.map +1 -0
- package/lib/typescript/src/NitroModalView.native.d.ts +3 -0
- package/lib/typescript/src/NitroModalView.native.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/nitro.json +23 -0
- package/nitrogen/generated/android/c++/JDismissReason.hpp +64 -0
- package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
- package/nitrogen/generated/android/c++/JFunc_void_DismissReason.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_ModalContentArea.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_double.hpp +75 -0
- package/nitrogen/generated/android/c++/JHybridNitroModalSpec.cpp +344 -0
- package/nitrogen/generated/android/c++/JHybridNitroModalSpec.hpp +106 -0
- package/nitrogen/generated/android/c++/JKeyboardBehavior.hpp +61 -0
- package/nitrogen/generated/android/c++/JModalContentArea.hpp +61 -0
- package/nitrogen/generated/android/c++/JModalMode.hpp +58 -0
- package/nitrogen/generated/android/c++/JPopupAnimation.hpp +61 -0
- package/nitrogen/generated/android/c++/JSheetDetent.hpp +64 -0
- package/nitrogen/generated/android/c++/views/JHybridNitroModalStateUpdater.cpp +174 -0
- package/nitrogen/generated/android/c++/views/JHybridNitroModalStateUpdater.hpp +54 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/DismissReason.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/Func_void.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/Func_void_DismissReason.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/Func_void_ModalContentArea.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/Func_void_double.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/HybridNitroModalSpec.kt +237 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/KeyboardBehavior.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/ModalContentArea.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/ModalMode.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/PopupAnimation.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/SheetDetent.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/nitromodalOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/views/HybridNitroModalManager.kt +96 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/views/HybridNitroModalStateUpdater.kt +23 -0
- package/nitrogen/generated/android/nitromodal+autolinking.cmake +83 -0
- package/nitrogen/generated/android/nitromodal+autolinking.gradle +27 -0
- package/nitrogen/generated/android/nitromodalOnLoad.cpp +64 -0
- package/nitrogen/generated/android/nitromodalOnLoad.hpp +34 -0
- package/nitrogen/generated/ios/NitroModal+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NitroModal-Swift-Cxx-Bridge.cpp +65 -0
- package/nitrogen/generated/ios/NitroModal-Swift-Cxx-Bridge.hpp +237 -0
- package/nitrogen/generated/ios/NitroModal-Swift-Cxx-Umbrella.hpp +64 -0
- package/nitrogen/generated/ios/NitroModalAutolinking.mm +33 -0
- package/nitrogen/generated/ios/NitroModalAutolinking.swift +26 -0
- package/nitrogen/generated/ios/c++/HybridNitroModalSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNitroModalSpecSwift.hpp +247 -0
- package/nitrogen/generated/ios/c++/views/HybridNitroModalComponent.mm +264 -0
- package/nitrogen/generated/ios/swift/DismissReason.swift +48 -0
- package/nitrogen/generated/ios/swift/Func_void.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_DismissReason.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_ModalContentArea.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_double.swift +46 -0
- package/nitrogen/generated/ios/swift/HybridNitroModalSpec.swift +77 -0
- package/nitrogen/generated/ios/swift/HybridNitroModalSpec_cxx.swift +554 -0
- package/nitrogen/generated/ios/swift/KeyboardBehavior.swift +44 -0
- package/nitrogen/generated/ios/swift/ModalContentArea.swift +34 -0
- package/nitrogen/generated/ios/swift/ModalMode.swift +40 -0
- package/nitrogen/generated/ios/swift/PopupAnimation.swift +44 -0
- package/nitrogen/generated/ios/swift/SheetDetent.swift +48 -0
- package/nitrogen/generated/shared/c++/DismissReason.hpp +84 -0
- package/nitrogen/generated/shared/c++/HybridNitroModalSpec.cpp +65 -0
- package/nitrogen/generated/shared/c++/HybridNitroModalSpec.hpp +124 -0
- package/nitrogen/generated/shared/c++/KeyboardBehavior.hpp +80 -0
- package/nitrogen/generated/shared/c++/ModalContentArea.hpp +87 -0
- package/nitrogen/generated/shared/c++/ModalMode.hpp +76 -0
- package/nitrogen/generated/shared/c++/PopupAnimation.hpp +80 -0
- package/nitrogen/generated/shared/c++/SheetDetent.hpp +84 -0
- package/nitrogen/generated/shared/c++/views/HybridNitroModalComponent.cpp +74 -0
- package/nitrogen/generated/shared/c++/views/HybridNitroModalComponent.hpp +151 -0
- package/nitrogen/generated/shared/json/NitroModalConfig.json +30 -0
- package/package.json +183 -0
- package/src/NitroModal.nitro.ts +92 -0
- package/src/NitroModal.tsx +292 -0
- package/src/NitroModalView.native.tsx +8 -0
- package/src/NitroModalView.tsx +24 -0
- package/src/index.tsx +12 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
//
|
|
2
|
+
// PopupViewController.swift
|
|
3
|
+
// NitroModal
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import UIKit
|
|
7
|
+
|
|
8
|
+
/// `popup` mode: a centered card over a full-screen backdrop, presented
|
|
9
|
+
/// `.overFullScreen` with a custom Core Animation transition.
|
|
10
|
+
final class PopupViewController: UIViewController, ModalPresenting, UIViewControllerTransitioningDelegate {
|
|
11
|
+
weak var presentationDelegate: ModalPresentationDelegate?
|
|
12
|
+
|
|
13
|
+
private static let margin: CGFloat = 16
|
|
14
|
+
private static let defaultCornerRadius: CGFloat = 16
|
|
15
|
+
|
|
16
|
+
private let contentView: NitroModalContentView
|
|
17
|
+
private let backdrop = BackdropView()
|
|
18
|
+
private let card = UIView()
|
|
19
|
+
private var config: ModalConfig
|
|
20
|
+
/// Portion of the view covered by the keyboard.
|
|
21
|
+
private var keyboardOverlap: CGFloat = 0
|
|
22
|
+
|
|
23
|
+
init(contentView: NitroModalContentView, config: ModalConfig) {
|
|
24
|
+
self.contentView = contentView
|
|
25
|
+
self.config = config
|
|
26
|
+
super.init(nibName: nil, bundle: nil)
|
|
27
|
+
modalPresentationStyle = .overFullScreen
|
|
28
|
+
transitioningDelegate = self
|
|
29
|
+
backdrop.onTap = { [weak self] in
|
|
30
|
+
self?.presentationDelegate?.modalPresentationDidTapBackdrop()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let center = NotificationCenter.default
|
|
34
|
+
center.addObserver(self, selector: #selector(keyboardWillChangeFrame(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
|
|
35
|
+
center.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@available(*, unavailable)
|
|
39
|
+
required init?(coder: NSCoder) {
|
|
40
|
+
fatalError("init(coder:) is not supported")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override func loadView() {
|
|
44
|
+
let root = UIView()
|
|
45
|
+
root.backgroundColor = .clear
|
|
46
|
+
|
|
47
|
+
backdrop.frame = root.bounds
|
|
48
|
+
backdrop.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
49
|
+
root.addSubview(backdrop)
|
|
50
|
+
|
|
51
|
+
card.clipsToBounds = true
|
|
52
|
+
card.layer.cornerCurve = .continuous
|
|
53
|
+
card.accessibilityViewIsModal = true
|
|
54
|
+
card.addSubview(contentView)
|
|
55
|
+
root.addSubview(card)
|
|
56
|
+
|
|
57
|
+
view = root
|
|
58
|
+
applyAppearance()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
override func viewDidLayoutSubviews() {
|
|
62
|
+
super.viewDidLayoutSubviews()
|
|
63
|
+
let available = availableRect(includingKeyboard: config.keyboardBehavior != .none)
|
|
64
|
+
let content = contentView.contentSize
|
|
65
|
+
// `bounds` + `center` keep the transition's scale transform intact.
|
|
66
|
+
card.bounds = CGRect(
|
|
67
|
+
origin: .zero,
|
|
68
|
+
size: CGSize(width: min(content.width, available.width), height: min(content.height, available.height))
|
|
69
|
+
)
|
|
70
|
+
card.center = CGPoint(x: available.midX, y: available.midY)
|
|
71
|
+
contentView.frame = card.bounds
|
|
72
|
+
|
|
73
|
+
let area = config.keyboardBehavior == .resize ? available : availableRect(includingKeyboard: false)
|
|
74
|
+
presentationDelegate?.modalPresentationDidChangeContentArea(area.size)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/// Animated state between hidden (0) and fully presented (1).
|
|
78
|
+
fileprivate func setTransitionProgress(_ progress: CGFloat, presenting: Bool) {
|
|
79
|
+
backdrop.alpha = progress
|
|
80
|
+
card.alpha = config.popupAnimation == .none ? 1 : progress
|
|
81
|
+
if config.popupAnimation == .scale && progress < 1 {
|
|
82
|
+
let scale: CGFloat = presenting ? 0.9 : 0.95
|
|
83
|
+
card.transform = CGAffineTransform(scaleX: scale, y: scale)
|
|
84
|
+
} else {
|
|
85
|
+
card.transform = .identity
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// MARK: ModalPresenting
|
|
90
|
+
|
|
91
|
+
func apply(_ newConfig: ModalConfig) {
|
|
92
|
+
config = newConfig
|
|
93
|
+
guard isViewLoaded else { return }
|
|
94
|
+
applyAppearance()
|
|
95
|
+
view.setNeedsLayout()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func contentSizeDidChange() {
|
|
99
|
+
guard isViewLoaded else { return }
|
|
100
|
+
UIView.animate(withDuration: 0.25, delay: 0, options: [.beginFromCurrentState, .allowUserInteraction]) {
|
|
101
|
+
self.view.setNeedsLayout()
|
|
102
|
+
self.view.layoutIfNeeded()
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func snapToDetent(at index: Int) {}
|
|
107
|
+
|
|
108
|
+
// MARK: UIViewControllerTransitioningDelegate
|
|
109
|
+
|
|
110
|
+
func animationController(
|
|
111
|
+
forPresented presented: UIViewController,
|
|
112
|
+
presenting: UIViewController,
|
|
113
|
+
source: UIViewController
|
|
114
|
+
) -> UIViewControllerAnimatedTransitioning? {
|
|
115
|
+
PopupTransition(presenting: true)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
|
119
|
+
PopupTransition(presenting: false)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// MARK: Private
|
|
123
|
+
|
|
124
|
+
private func applyAppearance() {
|
|
125
|
+
backdrop.configure(color: config.backdropColor, opacity: config.backdropOpacity, blurRadius: config.backdropBlurRadius)
|
|
126
|
+
card.backgroundColor = config.contentBackgroundColor
|
|
127
|
+
card.layer.cornerRadius = config.cornerRadius ?? Self.defaultCornerRadius
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/// Area a card may occupy inside `bounds`, keeping clear of the safe area.
|
|
131
|
+
static func availableRect(in bounds: CGRect, safeArea: UIEdgeInsets) -> CGRect {
|
|
132
|
+
bounds.inset(by: safeArea).insetBy(dx: margin, dy: margin)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private func availableRect(includingKeyboard: Bool) -> CGRect {
|
|
136
|
+
var rect = Self.availableRect(in: view.bounds, safeArea: view.safeAreaInsets)
|
|
137
|
+
if includingKeyboard {
|
|
138
|
+
let covered = max(0, keyboardOverlap - view.safeAreaInsets.bottom)
|
|
139
|
+
rect.size.height = max(0, rect.height - covered)
|
|
140
|
+
}
|
|
141
|
+
return rect
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@objc private func keyboardWillChangeFrame(_ notification: Notification) {
|
|
145
|
+
guard isViewLoaded, let window = view.window,
|
|
146
|
+
let frame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
|
|
147
|
+
let keyboard = view.convert(frame, from: window.screen.coordinateSpace)
|
|
148
|
+
updateKeyboardOverlap(max(0, view.bounds.maxY - keyboard.minY), notification: notification)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@objc private func keyboardWillHide(_ notification: Notification) {
|
|
152
|
+
guard isViewLoaded else { return }
|
|
153
|
+
updateKeyboardOverlap(0, notification: notification)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private func updateKeyboardOverlap(_ overlap: CGFloat, notification: Notification) {
|
|
157
|
+
guard overlap != keyboardOverlap else { return }
|
|
158
|
+
keyboardOverlap = overlap
|
|
159
|
+
guard config.keyboardBehavior != .none else { return }
|
|
160
|
+
notification.animateAlongsideKeyboard {
|
|
161
|
+
self.view.setNeedsLayout()
|
|
162
|
+
self.view.layoutIfNeeded()
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/// Fade/scale transition for `PopupViewController`, run by Core Animation.
|
|
168
|
+
private final class PopupTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
|
169
|
+
private let presenting: Bool
|
|
170
|
+
|
|
171
|
+
init(presenting: Bool) {
|
|
172
|
+
self.presenting = presenting
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
|
176
|
+
presenting ? 0.4 : 0.2
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
|
180
|
+
let key: UITransitionContextViewControllerKey = presenting ? .to : .from
|
|
181
|
+
guard let popup = transitionContext.viewController(forKey: key) as? PopupViewController else {
|
|
182
|
+
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if presenting {
|
|
187
|
+
popup.view.frame = transitionContext.finalFrame(for: popup)
|
|
188
|
+
transitionContext.containerView.addSubview(popup.view)
|
|
189
|
+
popup.view.layoutIfNeeded()
|
|
190
|
+
popup.setTransitionProgress(0, presenting: true)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
let finish: (Bool) -> Void = { _ in
|
|
194
|
+
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
195
|
+
}
|
|
196
|
+
guard transitionContext.isAnimated else {
|
|
197
|
+
popup.setTransitionProgress(presenting ? 1 : 0, presenting: presenting)
|
|
198
|
+
finish(true)
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let duration = transitionDuration(using: transitionContext)
|
|
203
|
+
if presenting {
|
|
204
|
+
UIView.animate(
|
|
205
|
+
withDuration: duration,
|
|
206
|
+
delay: 0,
|
|
207
|
+
usingSpringWithDamping: 0.82,
|
|
208
|
+
initialSpringVelocity: 0,
|
|
209
|
+
options: [.allowUserInteraction, .beginFromCurrentState],
|
|
210
|
+
animations: { popup.setTransitionProgress(1, presenting: true) },
|
|
211
|
+
completion: finish
|
|
212
|
+
)
|
|
213
|
+
} else {
|
|
214
|
+
UIView.animate(
|
|
215
|
+
withDuration: duration,
|
|
216
|
+
delay: 0,
|
|
217
|
+
options: [.curveEaseIn, .beginFromCurrentState],
|
|
218
|
+
animations: { popup.setTransitionProgress(0, presenting: false) },
|
|
219
|
+
completion: finish
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SheetViewController.swift
|
|
3
|
+
// NitroModal
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import UIKit
|
|
7
|
+
|
|
8
|
+
/// `bottomSheet` mode: a page sheet driven by `UISheetPresentationController`.
|
|
9
|
+
/// UIKit owns the pan gesture, detent snapping and swipe-to-dismiss, so all
|
|
10
|
+
/// of it runs on the render server with no JS involvement.
|
|
11
|
+
final class SheetViewController: UIViewController, ModalPresenting, UISheetPresentationControllerDelegate {
|
|
12
|
+
weak var presentationDelegate: ModalPresentationDelegate?
|
|
13
|
+
|
|
14
|
+
private let contentView: NitroModalContentView
|
|
15
|
+
private let backdrop = BackdropView()
|
|
16
|
+
private var config: ModalConfig
|
|
17
|
+
private var detentIdentifiers: [UISheetPresentationController.Detent.Identifier] = []
|
|
18
|
+
/// The latest `maximumDetentValue` UIKit handed to one of our detent resolvers.
|
|
19
|
+
private var maximumDetentValue: CGFloat?
|
|
20
|
+
private var keyboardHeight: CGFloat = 0
|
|
21
|
+
|
|
22
|
+
init(contentView: NitroModalContentView, config: ModalConfig) {
|
|
23
|
+
self.contentView = contentView
|
|
24
|
+
self.config = config
|
|
25
|
+
super.init(nibName: nil, bundle: nil)
|
|
26
|
+
modalPresentationStyle = .pageSheet
|
|
27
|
+
backdrop.onTap = { [weak self] in
|
|
28
|
+
self?.presentationDelegate?.modalPresentationDidTapBackdrop()
|
|
29
|
+
}
|
|
30
|
+
backdrop.configure(color: config.backdropColor, opacity: config.backdropOpacity, blurRadius: config.backdropBlurRadius)
|
|
31
|
+
configureSheet(selectingDetentAt: config.clampedInitialDetentIndex)
|
|
32
|
+
|
|
33
|
+
let center = NotificationCenter.default
|
|
34
|
+
center.addObserver(self, selector: #selector(keyboardWillChangeFrame(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
|
|
35
|
+
center.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@available(*, unavailable)
|
|
39
|
+
required init?(coder: NSCoder) {
|
|
40
|
+
fatalError("init(coder:) is not supported")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override func loadView() {
|
|
44
|
+
let root = UIView()
|
|
45
|
+
root.backgroundColor = config.contentBackgroundColor
|
|
46
|
+
root.accessibilityViewIsModal = true
|
|
47
|
+
contentView.frame = root.bounds
|
|
48
|
+
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
49
|
+
root.addSubview(contentView)
|
|
50
|
+
view = root
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override func viewWillAppear(_ animated: Bool) {
|
|
54
|
+
super.viewWillAppear(animated)
|
|
55
|
+
installBackdrop()
|
|
56
|
+
animateBackdrop(to: 1)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
override func viewWillDisappear(_ animated: Bool) {
|
|
60
|
+
super.viewWillDisappear(animated)
|
|
61
|
+
if isBeingDismissed || presentingViewController?.isBeingDismissed == true {
|
|
62
|
+
animateBackdrop(to: 0)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
override func viewDidLayoutSubviews() {
|
|
67
|
+
super.viewDidLayoutSubviews()
|
|
68
|
+
reportContentArea()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// MARK: ModalPresenting
|
|
72
|
+
|
|
73
|
+
func apply(_ newConfig: ModalConfig) {
|
|
74
|
+
let selectedIndex = sheetPresentationController?.selectedDetentIdentifier
|
|
75
|
+
.flatMap { detentIdentifiers.firstIndex(of: $0) }
|
|
76
|
+
config = newConfig
|
|
77
|
+
if isViewLoaded {
|
|
78
|
+
view.backgroundColor = config.contentBackgroundColor
|
|
79
|
+
}
|
|
80
|
+
backdrop.configure(color: config.backdropColor, opacity: config.backdropOpacity, blurRadius: config.backdropBlurRadius)
|
|
81
|
+
let index = min(selectedIndex ?? config.clampedInitialDetentIndex, max(config.detents.count - 1, 0))
|
|
82
|
+
guard let sheet = sheetPresentationController else { return }
|
|
83
|
+
sheet.animateChanges {
|
|
84
|
+
configureSheet(selectingDetentAt: index)
|
|
85
|
+
}
|
|
86
|
+
reportContentArea()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func contentSizeDidChange() {
|
|
90
|
+
guard config.detents.contains(.fitcontent), let sheet = sheetPresentationController else { return }
|
|
91
|
+
if #available(iOS 16.0, *) {
|
|
92
|
+
sheet.animateChanges {
|
|
93
|
+
sheet.invalidateDetents()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func snapToDetent(at index: Int) {
|
|
99
|
+
guard detentIdentifiers.indices.contains(index), let sheet = sheetPresentationController else { return }
|
|
100
|
+
sheet.animateChanges {
|
|
101
|
+
sheet.selectedDetentIdentifier = detentIdentifiers[index]
|
|
102
|
+
}
|
|
103
|
+
// UIKit only notifies the delegate for user-driven changes.
|
|
104
|
+
presentationDelegate?.modalPresentationDidChangeDetent(index)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// MARK: UISheetPresentationControllerDelegate
|
|
108
|
+
|
|
109
|
+
func sheetPresentationControllerDidChangeSelectedDetentIdentifier(_ sheet: UISheetPresentationController) {
|
|
110
|
+
guard let identifier = sheet.selectedDetentIdentifier,
|
|
111
|
+
let index = detentIdentifiers.firstIndex(of: identifier) else { return }
|
|
112
|
+
presentationDelegate?.modalPresentationDidChangeDetent(index)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
|
116
|
+
presentationDelegate?.modalPresentationDidDismissInteractively()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// MARK: Sheet configuration
|
|
120
|
+
|
|
121
|
+
private func configureSheet(selectingDetentAt index: Int) {
|
|
122
|
+
guard let sheet = sheetPresentationController else { return }
|
|
123
|
+
sheet.delegate = self
|
|
124
|
+
// Blocks swipe-to-dismiss while still allowing drags between detents.
|
|
125
|
+
isModalInPresentation = !config.dismissOnSwipe
|
|
126
|
+
sheet.prefersGrabberVisible = config.grabberVisible
|
|
127
|
+
sheet.preferredCornerRadius = config.cornerRadius
|
|
128
|
+
sheet.prefersScrollingExpandsWhenScrolledToEdge = true
|
|
129
|
+
sheet.prefersEdgeAttachedInCompactHeight = true
|
|
130
|
+
|
|
131
|
+
let (detents, identifiers) = makeDetents()
|
|
132
|
+
sheet.detents = detents
|
|
133
|
+
detentIdentifiers = identifiers
|
|
134
|
+
// `BackdropView` replaces the system dimming so color, opacity, blur and
|
|
135
|
+
// tap-outside are configurable. Undimming up to `.large` turns it off.
|
|
136
|
+
sheet.largestUndimmedDetentIdentifier = .large
|
|
137
|
+
if identifiers.indices.contains(index) {
|
|
138
|
+
sheet.selectedDetentIdentifier = identifiers[index]
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private func makeDetents() -> ([UISheetPresentationController.Detent], [UISheetPresentationController.Detent.Identifier]) {
|
|
143
|
+
let requested = config.detents.isEmpty ? [.fitcontent] : config.detents
|
|
144
|
+
guard #available(iOS 16.0, *) else {
|
|
145
|
+
// iOS 15 only has the two system detents, and `Detent.identifier` is iOS 16+.
|
|
146
|
+
let identifiers: [UISheetPresentationController.Detent.Identifier] = requested.map { $0 == .large ? .large : .medium }
|
|
147
|
+
return (identifiers.map { $0 == .large ? .large() : .medium() }, identifiers)
|
|
148
|
+
}
|
|
149
|
+
let detents = requested.enumerated().map { index, detent in
|
|
150
|
+
UISheetPresentationController.Detent.custom(
|
|
151
|
+
identifier: .init("nitro.\(index).\(detent.stringValue)")
|
|
152
|
+
) { [weak self] context in
|
|
153
|
+
self?.resolve(detent, maximum: context.maximumDetentValue)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return (detents, detents.map(\.identifier))
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/// Detent heights exclude the bottom safe area; UIKit adds it below.
|
|
160
|
+
private func resolve(_ detent: SheetDetent, maximum: CGFloat) -> CGFloat {
|
|
161
|
+
maximumDetentValue = maximum
|
|
162
|
+
switch detent {
|
|
163
|
+
case .small: return maximum * 0.25
|
|
164
|
+
case .medium: return maximum * 0.5
|
|
165
|
+
case .large: return maximum
|
|
166
|
+
case .fitcontent: return min(max(contentView.contentSize.height, 1), maximum)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// MARK: Backdrop
|
|
171
|
+
|
|
172
|
+
private func installBackdrop() {
|
|
173
|
+
guard let container = sheetPresentationController?.containerView, backdrop.superview !== container else { return }
|
|
174
|
+
backdrop.frame = container.bounds
|
|
175
|
+
backdrop.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
176
|
+
backdrop.alpha = 0
|
|
177
|
+
container.insertSubview(backdrop, at: 0)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/// Rides the transition coordinator so the backdrop tracks interactive
|
|
181
|
+
/// dismissals frame-by-frame and restores itself if the swipe is cancelled.
|
|
182
|
+
private func animateBackdrop(to alpha: CGFloat) {
|
|
183
|
+
guard let coordinator = transitionCoordinator else {
|
|
184
|
+
backdrop.alpha = alpha
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
let initial = backdrop.alpha
|
|
188
|
+
coordinator.animate(alongsideTransition: { [backdrop] _ in
|
|
189
|
+
backdrop.alpha = alpha
|
|
190
|
+
}, completion: { [backdrop] context in
|
|
191
|
+
if context.isCancelled {
|
|
192
|
+
backdrop.alpha = initial
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// MARK: Content area
|
|
198
|
+
|
|
199
|
+
private func reportContentArea() {
|
|
200
|
+
guard isViewLoaded, view.bounds.width > 0 else { return }
|
|
201
|
+
let maximum = maximumDetentValue ?? view.window.map(Self.estimatedMaximumDetentValue(in:)) ?? view.bounds.height
|
|
202
|
+
var height = Self.contentHeight(for: config.detents, maximum: maximum)
|
|
203
|
+
if config.keyboardBehavior == .resize {
|
|
204
|
+
height -= max(0, keyboardHeight - view.safeAreaInsets.bottom)
|
|
205
|
+
}
|
|
206
|
+
presentationDelegate?.modalPresentationDidChangeContentArea(CGSize(width: view.bounds.width, height: max(height, 0)))
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/// Height the content may occupy at the largest of `detents`.
|
|
210
|
+
static func contentHeight(for detents: [SheetDetent], maximum: CGFloat) -> CGFloat {
|
|
211
|
+
if detents.isEmpty || detents.contains(.large) || detents.contains(.fitcontent) {
|
|
212
|
+
return maximum
|
|
213
|
+
}
|
|
214
|
+
return detents.contains(.medium) ? maximum * 0.5 : maximum * 0.25
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/// Best guess of UIKit's `maximumDetentValue` before the sheet is on screen.
|
|
218
|
+
static func estimatedMaximumDetentValue(in window: UIWindow) -> CGFloat {
|
|
219
|
+
let insets = window.safeAreaInsets
|
|
220
|
+
return window.bounds.height - insets.top - insets.bottom - 10
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/// Best guess of the sheet width before it is on screen.
|
|
224
|
+
static func estimatedWidth(in window: UIWindow) -> CGFloat {
|
|
225
|
+
window.traitCollection.horizontalSizeClass == .regular ? min(window.bounds.width, 704) : window.bounds.width
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// MARK: Keyboard
|
|
229
|
+
|
|
230
|
+
// UIKit already lifts sheets above the keyboard; we only track the height
|
|
231
|
+
// so `resize` can shrink the area reported to the content.
|
|
232
|
+
@objc private func keyboardWillChangeFrame(_ notification: Notification) {
|
|
233
|
+
guard isViewLoaded, let window = view.window,
|
|
234
|
+
let frame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
|
|
235
|
+
let keyboard = window.convert(frame, from: window.screen.coordinateSpace)
|
|
236
|
+
keyboardHeight = max(0, window.bounds.maxY - keyboard.minY)
|
|
237
|
+
reportContentArea()
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@objc private func keyboardWillHide(_ notification: Notification) {
|
|
241
|
+
keyboardHeight = 0
|
|
242
|
+
reportContentArea()
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { processColor, StyleSheet, useWindowDimensions, View } from 'react-native';
|
|
5
|
+
import { callback } from 'react-native-nitro-modules';
|
|
6
|
+
import { NitroModalView } from './NitroModalView';
|
|
7
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
+
const DEFAULT_DETENTS = ['fitContent'];
|
|
9
|
+
const BLACK = 0xff000000;
|
|
10
|
+
function toNativeColor(color) {
|
|
11
|
+
if (color == null) return undefined;
|
|
12
|
+
const processed = processColor(color);
|
|
13
|
+
// PlatformColor / DynamicColorIOS objects are not supported.
|
|
14
|
+
return typeof processed === 'number' ? processed : undefined;
|
|
15
|
+
}
|
|
16
|
+
export function NitroModal({
|
|
17
|
+
isOpen,
|
|
18
|
+
mode = 'bottomSheet',
|
|
19
|
+
detents = DEFAULT_DETENTS,
|
|
20
|
+
initialDetentIndex = 0,
|
|
21
|
+
backdropColor = 'black',
|
|
22
|
+
backdropOpacity = 0.4,
|
|
23
|
+
backdropBlur = 0,
|
|
24
|
+
dismissOnBackdropPress = true,
|
|
25
|
+
dismissOnSwipe = true,
|
|
26
|
+
dismissOnBackButton = true,
|
|
27
|
+
showGrabber = false,
|
|
28
|
+
cornerRadius,
|
|
29
|
+
backgroundColor,
|
|
30
|
+
keyboardBehavior = 'pan',
|
|
31
|
+
popupAnimation = 'scale',
|
|
32
|
+
contentContainerStyle,
|
|
33
|
+
onPresent,
|
|
34
|
+
onDismiss,
|
|
35
|
+
onDetentChange,
|
|
36
|
+
onBackdropPress,
|
|
37
|
+
onBackButtonPress,
|
|
38
|
+
children,
|
|
39
|
+
testID,
|
|
40
|
+
ref
|
|
41
|
+
}) {
|
|
42
|
+
const isControlled = isOpen !== undefined;
|
|
43
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
44
|
+
const open = isControlled ? isOpen : internalOpen;
|
|
45
|
+
|
|
46
|
+
// Children mount when the modal opens and stay mounted until native reports
|
|
47
|
+
// that it is fully gone, so the exit animation still shows them.
|
|
48
|
+
const [sessionActive, setSessionActive] = useState(open);
|
|
49
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
50
|
+
if (open !== prevOpen) {
|
|
51
|
+
setPrevOpen(open);
|
|
52
|
+
if (open) setSessionActive(true);
|
|
53
|
+
}
|
|
54
|
+
const renderContent = open || sessionActive;
|
|
55
|
+
const [area, setArea] = useState(null);
|
|
56
|
+
const hybridRef = useRef(null);
|
|
57
|
+
|
|
58
|
+
// Native callbacks are created once (stable props, no native updates on
|
|
59
|
+
// re-render) and read the latest handlers from this ref.
|
|
60
|
+
const latest = useRef({
|
|
61
|
+
isControlled,
|
|
62
|
+
onPresent,
|
|
63
|
+
onDismiss,
|
|
64
|
+
onDetentChange,
|
|
65
|
+
onBackdropPress,
|
|
66
|
+
onBackButtonPress
|
|
67
|
+
});
|
|
68
|
+
useLayoutEffect(() => {
|
|
69
|
+
latest.current = {
|
|
70
|
+
isControlled,
|
|
71
|
+
onPresent,
|
|
72
|
+
onDismiss,
|
|
73
|
+
onDetentChange,
|
|
74
|
+
onBackdropPress,
|
|
75
|
+
onBackButtonPress
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
const nativeCallbacks = useMemo(() => ({
|
|
79
|
+
hybridRef: callback(instance => {
|
|
80
|
+
hybridRef.current = instance;
|
|
81
|
+
}),
|
|
82
|
+
onPresent: callback(() => {
|
|
83
|
+
setSessionActive(true);
|
|
84
|
+
latest.current.onPresent?.();
|
|
85
|
+
}),
|
|
86
|
+
onDismiss: callback(reason => {
|
|
87
|
+
setSessionActive(false);
|
|
88
|
+
if (!latest.current.isControlled) setInternalOpen(false);
|
|
89
|
+
latest.current.onDismiss?.(reason);
|
|
90
|
+
}),
|
|
91
|
+
onDetentChange: callback(index => {
|
|
92
|
+
latest.current.onDetentChange?.(index);
|
|
93
|
+
}),
|
|
94
|
+
onBackdropPress: callback(() => {
|
|
95
|
+
latest.current.onBackdropPress?.();
|
|
96
|
+
}),
|
|
97
|
+
onBackButtonPress: callback(() => {
|
|
98
|
+
latest.current.onBackButtonPress?.();
|
|
99
|
+
}),
|
|
100
|
+
onContentAreaChange: callback(next => {
|
|
101
|
+
setArea(current => current?.width === next.width && current.height === next.height ? current : next);
|
|
102
|
+
})
|
|
103
|
+
}), []);
|
|
104
|
+
useImperativeHandle(ref, () => ({
|
|
105
|
+
present: () => {
|
|
106
|
+
if (latest.current.isControlled) {
|
|
107
|
+
console.warn('NitroModal: present() is ignored while `isOpen` is controlled.');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
setInternalOpen(true);
|
|
111
|
+
},
|
|
112
|
+
dismiss: () => {
|
|
113
|
+
if (latest.current.isControlled) {
|
|
114
|
+
hybridRef.current?.dismiss();
|
|
115
|
+
} else {
|
|
116
|
+
setInternalOpen(false);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
snapToDetent: index => {
|
|
120
|
+
hybridRef.current?.snapToDetent(index);
|
|
121
|
+
}
|
|
122
|
+
}), []);
|
|
123
|
+
|
|
124
|
+
// Arrays are diffed by identity, so keep one instance per distinct value.
|
|
125
|
+
const detentsKey = detents.join(',');
|
|
126
|
+
const nativeDetents = useMemo(() => [...new Set(detentsKey.split(','))], [detentsKey]);
|
|
127
|
+
|
|
128
|
+
// Native reports the exact area; this only covers the first frame.
|
|
129
|
+
const windowSize = useWindowDimensions();
|
|
130
|
+
const contentArea = area ?? {
|
|
131
|
+
width: mode === 'popup' ? windowSize.width - 32 : windowSize.width,
|
|
132
|
+
height: mode === 'popup' ? windowSize.height - 160 : windowSize.height * 0.85
|
|
133
|
+
};
|
|
134
|
+
const containerStyle = mode === 'popup' ? {
|
|
135
|
+
maxWidth: contentArea.width,
|
|
136
|
+
maxHeight: contentArea.height
|
|
137
|
+
} : nativeDetents.includes('fitContent') ? {
|
|
138
|
+
width: contentArea.width,
|
|
139
|
+
maxHeight: contentArea.height
|
|
140
|
+
} : {
|
|
141
|
+
width: contentArea.width,
|
|
142
|
+
height: contentArea.height
|
|
143
|
+
};
|
|
144
|
+
return /*#__PURE__*/_jsx(NitroModalView, {
|
|
145
|
+
style: styles.host,
|
|
146
|
+
isOpen: open,
|
|
147
|
+
mode: mode,
|
|
148
|
+
detents: nativeDetents,
|
|
149
|
+
initialDetentIndex: initialDetentIndex,
|
|
150
|
+
backdropColor: toNativeColor(backdropColor) ?? BLACK,
|
|
151
|
+
backdropOpacity: backdropOpacity,
|
|
152
|
+
backdropBlurRadius: backdropBlur,
|
|
153
|
+
dismissOnBackdropPress: dismissOnBackdropPress,
|
|
154
|
+
dismissOnSwipe: dismissOnSwipe,
|
|
155
|
+
dismissOnBackButton: dismissOnBackButton,
|
|
156
|
+
grabberVisible: showGrabber,
|
|
157
|
+
cornerRadius: cornerRadius ?? -1,
|
|
158
|
+
contentBackgroundColor: toNativeColor(backgroundColor),
|
|
159
|
+
keyboardBehavior: keyboardBehavior,
|
|
160
|
+
popupAnimation: popupAnimation,
|
|
161
|
+
...nativeCallbacks,
|
|
162
|
+
children: renderContent ? /*#__PURE__*/_jsx(View, {
|
|
163
|
+
collapsable: false,
|
|
164
|
+
testID: testID,
|
|
165
|
+
style: [styles.container, containerStyle, contentContainerStyle],
|
|
166
|
+
children: children
|
|
167
|
+
}) : null
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const styles = StyleSheet.create({
|
|
171
|
+
// Zero-size placeholder in the React tree; the content renders natively in
|
|
172
|
+
// the modal's own window / view controller.
|
|
173
|
+
host: {
|
|
174
|
+
position: 'absolute',
|
|
175
|
+
left: 0,
|
|
176
|
+
top: 0,
|
|
177
|
+
width: 0,
|
|
178
|
+
height: 0
|
|
179
|
+
},
|
|
180
|
+
// Pinned at the origin: native hosts it at the top of the sheet / the
|
|
181
|
+
// card, and uses its measured size for `fitContent` and the card size.
|
|
182
|
+
container: {
|
|
183
|
+
position: 'absolute',
|
|
184
|
+
left: 0,
|
|
185
|
+
top: 0
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
//# sourceMappingURL=NitroModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useImperativeHandle","useLayoutEffect","useMemo","useRef","useState","processColor","StyleSheet","useWindowDimensions","View","callback","NitroModalView","jsx","_jsx","DEFAULT_DETENTS","BLACK","toNativeColor","color","undefined","processed","NitroModal","isOpen","mode","detents","initialDetentIndex","backdropColor","backdropOpacity","backdropBlur","dismissOnBackdropPress","dismissOnSwipe","dismissOnBackButton","showGrabber","cornerRadius","backgroundColor","keyboardBehavior","popupAnimation","contentContainerStyle","onPresent","onDismiss","onDetentChange","onBackdropPress","onBackButtonPress","children","testID","ref","isControlled","internalOpen","setInternalOpen","open","sessionActive","setSessionActive","prevOpen","setPrevOpen","renderContent","area","setArea","hybridRef","latest","current","nativeCallbacks","instance","reason","index","onContentAreaChange","next","width","height","present","console","warn","dismiss","snapToDetent","detentsKey","join","nativeDetents","Set","split","windowSize","contentArea","containerStyle","maxWidth","maxHeight","includes","style","styles","host","backdropBlurRadius","grabberVisible","contentBackgroundColor","collapsable","container","create","position","left","top"],"sourceRoot":"../../src","sources":["NitroModal.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["NitroModal.nitro.ts"],"mappings":"","ignoreList":[]}
|