Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions Package.resolved

This file was deleted.

8 changes: 2 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,11 @@ let package = Package(
products: [
.library(name: "PopupView", targets: ["PopupView"]),
],
dependencies: [
.package(url: "https://github.com/siteline/swiftui-introspect", "1.3.0"..<"27.0.0"),
],
dependencies: [],
targets: [
.target(
name: "PopupView",
dependencies: [
.product(name: "SwiftUIIntrospect", package: "swiftui-introspect"),
],
dependencies: [],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
]
Expand Down

This file was deleted.

2 changes: 1 addition & 1 deletion PopupExample/PopupExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ struct ContentView : View {
ActionSheetSecond()
} customize: {
$0
.type(.scroll(headerView: AnyView(scrollViewHeader())))
.type(.scroll(headerView: scrollViewHeader()))
.position(.bottom)
.closeOnTap(false)
.closeOnTapOutside(true)
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@ scroll parameters:
`autohideIn` - time after which popup should disappear
`dismissibleIn(Double?, Binding<Bool>?)` - only allow dismiss after this time passes (forbids closeOnTap, closeOnTapOutside, and drag). Pass a boolean binding if you'd like to track current status
`dragToDismiss` - true by default: enable/disable drag to dismiss (upwards for .top popup types, downwards for .bottom and default type)
`closeOnTap` - true by default: enable/disable closing on tap on popup
`closeOnTap` - true by default: enable/disable closing on tap on popup.
NOTE: any gesture or control element you add to popup's body will override tap to close. in this case please close the popup manually if you need it to
`closeOnTapOutside` - false by default: enable/disable closing on tap on outside of popup
`allowTapThroughBG` - Should allow taps to pass "through" the popup's background down to views "below" it. `.sheet` popup is always allowTapThroughBG = false. False by default
`backgroundColor` - Color.clear by default: change background color of outside area
Expand Down
1 change: 1 addition & 0 deletions Sources/PopupView/PopupScrollViewDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ final class PopupScrollViewDelegate: ObservableObject {
let maxContentOffset = (scrollView?.maxContentOffsetHeight() ?? 0) + keyboardHeightHelper.keyboardHeight

if contentOffset - translation.y > 0 {
didReachTop(0)
scrollView?.contentOffset.y = min(contentOffset - translation.y, maxContentOffset)
gesture.setTranslation(.zero, in: scrollView)
} else {
Expand Down
43 changes: 35 additions & 8 deletions Sources/PopupView/PopupView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
//

import SwiftUI
#if os(iOS)
@_spi(Advanced) import SwiftUIIntrospect
#endif

public struct Popup<PopupContent: View>: ViewModifier {

Expand Down Expand Up @@ -381,20 +378,37 @@ public struct Popup<PopupContent: View>: ViewModifier {
@ViewBuilder
private func contentView() -> some View {
#if os(iOS)
let dragGesture = DragGesture()
.updating($dragState) { drag, state, _ in
if !isDragging {
DispatchQueue.main.async {
isDragging = true
}
}
state = .dragging(translation: drag.translation)
}
.onEnded(onDragEnded)

switch type {
case .scroll(let headerView):
VStack(spacing: 0) {
headerView
scrollHeaderView(view: headerView)
.fixedSize(horizontal: false, vertical: true)
.offset(dragOffset())
.simultaneousGesture(dragGesture)

ScrollView {
view()
.background(
ScrollViewResolver { scrollView in
configure(scrollView: scrollView)
}
)
}
// no heigher than its contents
.frame(maxHeight: scrollViewContentHeight)
.frameGetter($scrollViewRect)
}
.introspect(.scrollView, on: .iOS(.v15...)) { scrollView in
configure(scrollView: scrollView)
.offset(dragOffset())
}
.offset(CGSize(width: 0, height: scrollViewOffset.height))

Expand All @@ -406,6 +420,18 @@ public struct Popup<PopupContent: View>: ViewModifier {
#endif
}

#if os(iOS)
@ViewBuilder
func scrollHeaderView(view: any View) -> some View {
ZStack {
Color.white
.mask(AnyView(view))

AnyView(view)
}
}
#endif

#if swift(>=5.9)
/// This is the builder for the sheet content
@ViewBuilder
Expand Down Expand Up @@ -452,7 +478,7 @@ public struct Popup<PopupContent: View>: ViewModifier {
.onChange(of: sheetContentRect.size) { sheetContentRect in
#if os(iOS)
// check if scrollView has already calculated its height, otherwise sheetContentRect is already non-zero but yet incorrect
if case .scroll(_) = type, scrollViewRect.height == 0 {
if case .scroll = type, scrollViewRect.height == 0 {
return
}
#endif
Expand Down Expand Up @@ -646,3 +672,4 @@ public struct Popup<PopupContent: View>: ViewModifier {
}
#endif
}

4 changes: 3 additions & 1 deletion Sources/PopupView/PublicAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extension Popup {
case toast
case floater(verticalPadding: CGFloat = 10, horizontalPadding: CGFloat = 10, useSafeAreaInset: Bool = true)
#if os(iOS)
case scroll(headerView: AnyView = AnyView(Color.clear.frame(height: 1)))
case scroll(headerView: any View = EmptyView())
#endif

var defaultPosition: Position {
Expand Down Expand Up @@ -135,6 +135,7 @@ extension Popup {
var dragToDismissDistance: CGFloat?

/// Should close on tap - default is `true`
/// NOTE: any gesture or control element you add to popup's body will override tap to close. in this case please close the popup manually if you need it to
var closeOnTap: Bool = true

/// Should close on tap outside - default is `false`
Expand Down Expand Up @@ -225,6 +226,7 @@ extension Popup {
}

/// Should close on tap - default is `true`
/// NOTE: any gesture or control element you add to popup's body will override tap to close. in this case please close the popup manually if you need it to
public func closeOnTap(_ closeOnTap: Bool) -> PopupParameters {
var params = self
params.closeOnTap = closeOnTap
Expand Down
35 changes: 34 additions & 1 deletion Sources/PopupView/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ extension View {
self
#else
if condition {
self.simultaneousGesture(
self.gesture(
TapGesture().onEnded {
onTap()
}
Expand Down Expand Up @@ -281,3 +281,36 @@ extension CGSize {
#endif
}
}

#if os(iOS)
// MARK: ScrollViewResolver

struct ScrollViewResolver: UIViewRepresentable {
var onResolve: (UIScrollView) -> Void

func makeUIView(context: Context) -> UIView {
let view = UIView()
DispatchQueue.main.async {
if let scrollView = view.enclosingScrollView() {
onResolve(scrollView)
}
}
return view
}

func updateUIView(_ uiView: UIView, context: Context) {}
}

extension UIView {
func enclosingScrollView() -> UIScrollView? {
var view = self.superview
while view != nil {
if let scroll = view as? UIScrollView {
return scroll
}
view = view?.superview
}
return nil
}
}
#endif