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.
Files changed (117) hide show
  1. package/LICENSE +20 -0
  2. package/NitroModal.podspec +29 -0
  3. package/README.md +39 -0
  4. package/android/CMakeLists.txt +24 -0
  5. package/android/build.gradle +124 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/cpp-adapter.cpp +11 -0
  8. package/android/src/main/java/com/margelo/nitro/nitromodal/BottomSheetPresenter.kt +284 -0
  9. package/android/src/main/java/com/margelo/nitro/nitromodal/HybridNitroModal.kt +312 -0
  10. package/android/src/main/java/com/margelo/nitro/nitromodal/ModalConfig.kt +50 -0
  11. package/android/src/main/java/com/margelo/nitro/nitromodal/ModalContentRoot.kt +115 -0
  12. package/android/src/main/java/com/margelo/nitro/nitromodal/ModalPresenter.kt +253 -0
  13. package/android/src/main/java/com/margelo/nitro/nitromodal/NitroModalHostView.kt +52 -0
  14. package/android/src/main/java/com/margelo/nitro/nitromodal/NitroModalPackage.kt +28 -0
  15. package/android/src/main/java/com/margelo/nitro/nitromodal/NitroModalViewManager.kt +67 -0
  16. package/android/src/main/java/com/margelo/nitro/nitromodal/PopupPresenter.kt +156 -0
  17. package/android/src/main/res/values/styles.xml +17 -0
  18. package/ios/BackdropView.swift +64 -0
  19. package/ios/HybridNitroModal.swift +329 -0
  20. package/ios/HybridNitroModalComponent+Children.mm +77 -0
  21. package/ios/ModalConfig.swift +73 -0
  22. package/ios/NitroModalHostView.swift +91 -0
  23. package/ios/PopupViewController.swift +223 -0
  24. package/ios/SheetViewController.swift +244 -0
  25. package/lib/module/NitroModal.js +188 -0
  26. package/lib/module/NitroModal.js.map +1 -0
  27. package/lib/module/NitroModal.nitro.js +4 -0
  28. package/lib/module/NitroModal.nitro.js.map +1 -0
  29. package/lib/module/NitroModalView.js +17 -0
  30. package/lib/module/NitroModalView.js.map +1 -0
  31. package/lib/module/NitroModalView.native.js +6 -0
  32. package/lib/module/NitroModalView.native.js.map +1 -0
  33. package/lib/module/index.js +4 -0
  34. package/lib/module/index.js.map +1 -0
  35. package/lib/module/package.json +1 -0
  36. package/lib/typescript/package.json +1 -0
  37. package/lib/typescript/src/NitroModal.d.ts +59 -0
  38. package/lib/typescript/src/NitroModal.d.ts.map +1 -0
  39. package/lib/typescript/src/NitroModal.nitro.d.ts +78 -0
  40. package/lib/typescript/src/NitroModal.nitro.d.ts.map +1 -0
  41. package/lib/typescript/src/NitroModalView.d.ts +4 -0
  42. package/lib/typescript/src/NitroModalView.d.ts.map +1 -0
  43. package/lib/typescript/src/NitroModalView.native.d.ts +3 -0
  44. package/lib/typescript/src/NitroModalView.native.d.ts.map +1 -0
  45. package/lib/typescript/src/index.d.ts +3 -0
  46. package/lib/typescript/src/index.d.ts.map +1 -0
  47. package/nitro.json +23 -0
  48. package/nitrogen/generated/android/c++/JDismissReason.hpp +64 -0
  49. package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
  50. package/nitrogen/generated/android/c++/JFunc_void_DismissReason.hpp +77 -0
  51. package/nitrogen/generated/android/c++/JFunc_void_ModalContentArea.hpp +77 -0
  52. package/nitrogen/generated/android/c++/JFunc_void_double.hpp +75 -0
  53. package/nitrogen/generated/android/c++/JHybridNitroModalSpec.cpp +344 -0
  54. package/nitrogen/generated/android/c++/JHybridNitroModalSpec.hpp +106 -0
  55. package/nitrogen/generated/android/c++/JKeyboardBehavior.hpp +61 -0
  56. package/nitrogen/generated/android/c++/JModalContentArea.hpp +61 -0
  57. package/nitrogen/generated/android/c++/JModalMode.hpp +58 -0
  58. package/nitrogen/generated/android/c++/JPopupAnimation.hpp +61 -0
  59. package/nitrogen/generated/android/c++/JSheetDetent.hpp +64 -0
  60. package/nitrogen/generated/android/c++/views/JHybridNitroModalStateUpdater.cpp +174 -0
  61. package/nitrogen/generated/android/c++/views/JHybridNitroModalStateUpdater.hpp +54 -0
  62. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/DismissReason.kt +25 -0
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/Func_void.kt +78 -0
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/Func_void_DismissReason.kt +78 -0
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/Func_void_ModalContentArea.kt +78 -0
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/Func_void_double.kt +78 -0
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/HybridNitroModalSpec.kt +237 -0
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/KeyboardBehavior.kt +24 -0
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/ModalContentArea.kt +56 -0
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/ModalMode.kt +23 -0
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/PopupAnimation.kt +24 -0
  72. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/SheetDetent.kt +25 -0
  73. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/nitromodalOnLoad.kt +35 -0
  74. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/views/HybridNitroModalManager.kt +96 -0
  75. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromodal/views/HybridNitroModalStateUpdater.kt +23 -0
  76. package/nitrogen/generated/android/nitromodal+autolinking.cmake +83 -0
  77. package/nitrogen/generated/android/nitromodal+autolinking.gradle +27 -0
  78. package/nitrogen/generated/android/nitromodalOnLoad.cpp +64 -0
  79. package/nitrogen/generated/android/nitromodalOnLoad.hpp +34 -0
  80. package/nitrogen/generated/ios/NitroModal+autolinking.rb +62 -0
  81. package/nitrogen/generated/ios/NitroModal-Swift-Cxx-Bridge.cpp +65 -0
  82. package/nitrogen/generated/ios/NitroModal-Swift-Cxx-Bridge.hpp +237 -0
  83. package/nitrogen/generated/ios/NitroModal-Swift-Cxx-Umbrella.hpp +64 -0
  84. package/nitrogen/generated/ios/NitroModalAutolinking.mm +33 -0
  85. package/nitrogen/generated/ios/NitroModalAutolinking.swift +26 -0
  86. package/nitrogen/generated/ios/c++/HybridNitroModalSpecSwift.cpp +11 -0
  87. package/nitrogen/generated/ios/c++/HybridNitroModalSpecSwift.hpp +247 -0
  88. package/nitrogen/generated/ios/c++/views/HybridNitroModalComponent.mm +264 -0
  89. package/nitrogen/generated/ios/swift/DismissReason.swift +48 -0
  90. package/nitrogen/generated/ios/swift/Func_void.swift +46 -0
  91. package/nitrogen/generated/ios/swift/Func_void_DismissReason.swift +46 -0
  92. package/nitrogen/generated/ios/swift/Func_void_ModalContentArea.swift +46 -0
  93. package/nitrogen/generated/ios/swift/Func_void_double.swift +46 -0
  94. package/nitrogen/generated/ios/swift/HybridNitroModalSpec.swift +77 -0
  95. package/nitrogen/generated/ios/swift/HybridNitroModalSpec_cxx.swift +554 -0
  96. package/nitrogen/generated/ios/swift/KeyboardBehavior.swift +44 -0
  97. package/nitrogen/generated/ios/swift/ModalContentArea.swift +34 -0
  98. package/nitrogen/generated/ios/swift/ModalMode.swift +40 -0
  99. package/nitrogen/generated/ios/swift/PopupAnimation.swift +44 -0
  100. package/nitrogen/generated/ios/swift/SheetDetent.swift +48 -0
  101. package/nitrogen/generated/shared/c++/DismissReason.hpp +84 -0
  102. package/nitrogen/generated/shared/c++/HybridNitroModalSpec.cpp +65 -0
  103. package/nitrogen/generated/shared/c++/HybridNitroModalSpec.hpp +124 -0
  104. package/nitrogen/generated/shared/c++/KeyboardBehavior.hpp +80 -0
  105. package/nitrogen/generated/shared/c++/ModalContentArea.hpp +87 -0
  106. package/nitrogen/generated/shared/c++/ModalMode.hpp +76 -0
  107. package/nitrogen/generated/shared/c++/PopupAnimation.hpp +80 -0
  108. package/nitrogen/generated/shared/c++/SheetDetent.hpp +84 -0
  109. package/nitrogen/generated/shared/c++/views/HybridNitroModalComponent.cpp +74 -0
  110. package/nitrogen/generated/shared/c++/views/HybridNitroModalComponent.hpp +151 -0
  111. package/nitrogen/generated/shared/json/NitroModalConfig.json +30 -0
  112. package/package.json +183 -0
  113. package/src/NitroModal.nitro.ts +92 -0
  114. package/src/NitroModal.tsx +292 -0
  115. package/src/NitroModalView.native.tsx +8 -0
  116. package/src/NitroModalView.tsx +24 -0
  117. 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":";;AAAA,SACEA,mBAAmB,EACnBC,eAAe,EACfC,OAAO,EACPC,MAAM,EACNC,QAAQ,QAGH,OAAO;AACd,SACEC,YAAY,EACZC,UAAU,EACVC,mBAAmB,EACnBC,IAAI,QAIC,cAAc;AACrB,SAASC,QAAQ,QAAQ,4BAA4B;AAUrD,SAASC,cAAc,QAAQ,kBAAkB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AA0DlD,MAAMC,eAA8B,GAAG,CAAC,YAAY,CAAC;AACrD,MAAMC,KAAK,GAAG,UAAU;AAExB,SAASC,aAAaA,CAACC,KAA6B,EAAsB;EACxE,IAAIA,KAAK,IAAI,IAAI,EAAE,OAAOC,SAAS;EACnC,MAAMC,SAAS,GAAGb,YAAY,CAACW,KAAK,CAAC;EACrC;EACA,OAAO,OAAOE,SAAS,KAAK,QAAQ,GAAGA,SAAS,GAAGD,SAAS;AAC9D;AAEA,OAAO,SAASE,UAAUA,CAAC;EACzBC,MAAM;EACNC,IAAI,GAAG,aAAa;EACpBC,OAAO,GAAGT,eAAe;EACzBU,kBAAkB,GAAG,CAAC;EACtBC,aAAa,GAAG,OAAO;EACvBC,eAAe,GAAG,GAAG;EACrBC,YAAY,GAAG,CAAC;EAChBC,sBAAsB,GAAG,IAAI;EAC7BC,cAAc,GAAG,IAAI;EACrBC,mBAAmB,GAAG,IAAI;EAC1BC,WAAW,GAAG,KAAK;EACnBC,YAAY;EACZC,eAAe;EACfC,gBAAgB,GAAG,KAAK;EACxBC,cAAc,GAAG,OAAO;EACxBC,qBAAqB;EACrBC,SAAS;EACTC,SAAS;EACTC,cAAc;EACdC,eAAe;EACfC,iBAAiB;EACjBC,QAAQ;EACRC,MAAM;EACNC;AACe,CAAC,EAAE;EAClB,MAAMC,YAAY,GAAGxB,MAAM,KAAKH,SAAS;EACzC,MAAM,CAAC4B,YAAY,EAAEC,eAAe,CAAC,GAAG1C,QAAQ,CAAC,KAAK,CAAC;EACvD,MAAM2C,IAAI,GAAGH,YAAY,GAAGxB,MAAM,GAAGyB,YAAY;;EAEjD;EACA;EACA,MAAM,CAACG,aAAa,EAAEC,gBAAgB,CAAC,GAAG7C,QAAQ,CAAC2C,IAAI,CAAC;EACxD,MAAM,CAACG,QAAQ,EAAEC,WAAW,CAAC,GAAG/C,QAAQ,CAAC2C,IAAI,CAAC;EAC9C,IAAIA,IAAI,KAAKG,QAAQ,EAAE;IACrBC,WAAW,CAACJ,IAAI,CAAC;IACjB,IAAIA,IAAI,EAAEE,gBAAgB,CAAC,IAAI,CAAC;EAClC;EACA,MAAMG,aAAa,GAAGL,IAAI,IAAIC,aAAa;EAE3C,MAAM,CAACK,IAAI,EAAEC,OAAO,CAAC,GAAGlD,QAAQ,CAA0B,IAAI,CAAC;EAC/D,MAAMmD,SAAS,GAAGpD,MAAM,CAA8B,IAAI,CAAC;;EAE3D;EACA;EACA,MAAMqD,MAAM,GAAGrD,MAAM,CAAC;IACpByC,YAAY;IACZR,SAAS;IACTC,SAAS;IACTC,cAAc;IACdC,eAAe;IACfC;EACF,CAAC,CAAC;EACFvC,eAAe,CAAC,MAAM;IACpBuD,MAAM,CAACC,OAAO,GAAG;MACfb,YAAY;MACZR,SAAS;MACTC,SAAS;MACTC,cAAc;MACdC,eAAe;MACfC;IACF,CAAC;EACH,CAAC,CAAC;EAEF,MAAMkB,eAAe,GAAGxD,OAAO,CAC7B,OAAO;IACLqD,SAAS,EAAE9C,QAAQ,CAAEkD,QAA8B,IAAK;MACtDJ,SAAS,CAACE,OAAO,GAAGE,QAAQ;IAC9B,CAAC,CAAC;IACFvB,SAAS,EAAE3B,QAAQ,CAAC,MAAM;MACxBwC,gBAAgB,CAAC,IAAI,CAAC;MACtBO,MAAM,CAACC,OAAO,CAACrB,SAAS,GAAG,CAAC;IAC9B,CAAC,CAAC;IACFC,SAAS,EAAE5B,QAAQ,CAAEmD,MAAqB,IAAK;MAC7CX,gBAAgB,CAAC,KAAK,CAAC;MACvB,IAAI,CAACO,MAAM,CAACC,OAAO,CAACb,YAAY,EAAEE,eAAe,CAAC,KAAK,CAAC;MACxDU,MAAM,CAACC,OAAO,CAACpB,SAAS,GAAGuB,MAAM,CAAC;IACpC,CAAC,CAAC;IACFtB,cAAc,EAAE7B,QAAQ,CAAEoD,KAAa,IAAK;MAC1CL,MAAM,CAACC,OAAO,CAACnB,cAAc,GAAGuB,KAAK,CAAC;IACxC,CAAC,CAAC;IACFtB,eAAe,EAAE9B,QAAQ,CAAC,MAAM;MAC9B+C,MAAM,CAACC,OAAO,CAAClB,eAAe,GAAG,CAAC;IACpC,CAAC,CAAC;IACFC,iBAAiB,EAAE/B,QAAQ,CAAC,MAAM;MAChC+C,MAAM,CAACC,OAAO,CAACjB,iBAAiB,GAAG,CAAC;IACtC,CAAC,CAAC;IACFsB,mBAAmB,EAAErD,QAAQ,CAAEsD,IAAsB,IAAK;MACxDT,OAAO,CAAEG,OAAO,IACdA,OAAO,EAAEO,KAAK,KAAKD,IAAI,CAACC,KAAK,IAAIP,OAAO,CAACQ,MAAM,KAAKF,IAAI,CAACE,MAAM,GAC3DR,OAAO,GACPM,IACN,CAAC;IACH,CAAC;EACH,CAAC,CAAC,EACF,EACF,CAAC;EAED/D,mBAAmB,CACjB2C,GAAG,EACH,OAAO;IACLuB,OAAO,EAAEA,CAAA,KAAM;MACb,IAAIV,MAAM,CAACC,OAAO,CAACb,YAAY,EAAE;QAC/BuB,OAAO,CAACC,IAAI,CACV,gEACF,CAAC;QACD;MACF;MACAtB,eAAe,CAAC,IAAI,CAAC;IACvB,CAAC;IACDuB,OAAO,EAAEA,CAAA,KAAM;MACb,IAAIb,MAAM,CAACC,OAAO,CAACb,YAAY,EAAE;QAC/BW,SAAS,CAACE,OAAO,EAAEY,OAAO,CAAC,CAAC;MAC9B,CAAC,MAAM;QACLvB,eAAe,CAAC,KAAK,CAAC;MACxB;IACF,CAAC;IACDwB,YAAY,EAAGT,KAAa,IAAK;MAC/BN,SAAS,CAACE,OAAO,EAAEa,YAAY,CAACT,KAAK,CAAC;IACxC;EACF,CAAC,CAAC,EACF,EACF,CAAC;;EAED;EACA,MAAMU,UAAU,GAAGjD,OAAO,CAACkD,IAAI,CAAC,GAAG,CAAC;EACpC,MAAMC,aAAa,GAAGvE,OAAO,CAC3B,MAAM,CAAC,GAAG,IAAIwE,GAAG,CAACH,UAAU,CAACI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAkB,EAC1D,CAACJ,UAAU,CACb,CAAC;;EAED;EACA,MAAMK,UAAU,GAAGrE,mBAAmB,CAAC,CAAC;EACxC,MAAMsE,WAAW,GAAGxB,IAAI,IAAI;IAC1BW,KAAK,EAAE3C,IAAI,KAAK,OAAO,GAAGuD,UAAU,CAACZ,KAAK,GAAG,EAAE,GAAGY,UAAU,CAACZ,KAAK;IAClEC,MAAM,EACJ5C,IAAI,KAAK,OAAO,GAAGuD,UAAU,CAACX,MAAM,GAAG,GAAG,GAAGW,UAAU,CAACX,MAAM,GAAG;EACrE,CAAC;EACD,MAAMa,cAAyB,GAC7BzD,IAAI,KAAK,OAAO,GACZ;IAAE0D,QAAQ,EAAEF,WAAW,CAACb,KAAK;IAAEgB,SAAS,EAAEH,WAAW,CAACZ;EAAO,CAAC,GAC9DQ,aAAa,CAACQ,QAAQ,CAAC,YAAY,CAAC,GAClC;IAAEjB,KAAK,EAAEa,WAAW,CAACb,KAAK;IAAEgB,SAAS,EAAEH,WAAW,CAACZ;EAAO,CAAC,GAC3D;IAAED,KAAK,EAAEa,WAAW,CAACb,KAAK;IAAEC,MAAM,EAAEY,WAAW,CAACZ;EAAO,CAAC;EAEhE,oBACErD,IAAA,CAACF,cAAc;IACbwE,KAAK,EAAEC,MAAM,CAACC,IAAK;IACnBhE,MAAM,EAAE2B,IAAK;IACb1B,IAAI,EAAEA,IAAK;IACXC,OAAO,EAAEmD,aAAc;IACvBlD,kBAAkB,EAAEA,kBAAmB;IACvCC,aAAa,EAAET,aAAa,CAACS,aAAa,CAAC,IAAIV,KAAM;IACrDW,eAAe,EAAEA,eAAgB;IACjC4D,kBAAkB,EAAE3D,YAAa;IACjCC,sBAAsB,EAAEA,sBAAuB;IAC/CC,cAAc,EAAEA,cAAe;IAC/BC,mBAAmB,EAAEA,mBAAoB;IACzCyD,cAAc,EAAExD,WAAY;IAC5BC,YAAY,EAAEA,YAAY,IAAI,CAAC,CAAE;IACjCwD,sBAAsB,EAAExE,aAAa,CAACiB,eAAe,CAAE;IACvDC,gBAAgB,EAAEA,gBAAiB;IACnCC,cAAc,EAAEA,cAAe;IAAA,GAC3BwB,eAAe;IAAAjB,QAAA,EAElBW,aAAa,gBACZxC,IAAA,CAACJ,IAAI;MACHgF,WAAW,EAAE,KAAM;MACnB9C,MAAM,EAAEA,MAAO;MACfwC,KAAK,EAAE,CAACC,MAAM,CAACM,SAAS,EAAEX,cAAc,EAAE3C,qBAAqB,CAAE;MAAAM,QAAA,EAEhEA;IAAQ,CACL,CAAC,GACL;EAAI,CACM,CAAC;AAErB;AAEA,MAAM0C,MAAM,GAAG7E,UAAU,CAACoF,MAAM,CAAC;EAC/B;EACA;EACAN,IAAI,EAAE;IACJO,QAAQ,EAAE,UAAU;IACpBC,IAAI,EAAE,CAAC;IACPC,GAAG,EAAE,CAAC;IACN7B,KAAK,EAAE,CAAC;IACRC,MAAM,EAAE;EACV,CAAC;EACD;EACA;EACAwB,SAAS,EAAE;IACTE,QAAQ,EAAE,UAAU;IACpBC,IAAI,EAAE,CAAC;IACPC,GAAG,EAAE;EACP;AACF,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export {};
4
+ //# sourceMappingURL=NitroModal.nitro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["NitroModal.nitro.ts"],"mappings":"","ignoreList":[]}