@@ -72,6 +72,7 @@ struct SliderMenuItem: View {
7272 @State var isSheetVisible = false
7373
7474 @State var detentHeight : CGFloat = 0
75+ @State var barItemFrame : CGRect = . zero
7576
7677 var onUpdate : ( ) -> Void
7778
@@ -85,7 +86,7 @@ struct SliderMenuItem: View {
8586 . onTapGesture {
8687 self . isSheetVisible. toggle ( )
8788 }
88- . popover ( isPresented: self . $isSheetVisible) {
89+ . popover ( isPresented: self . $isSheetVisible, arrowEdge : self . barItemFrame . arrowDirection ( ) ) {
8990 CancellableResettableDialogForm {
9091 SortFilterItemTitle ( title: self . item. name)
9192 } cancelAction: {
@@ -120,6 +121,17 @@ struct SliderMenuItem: View {
120121 }
121122 . presentationDetents ( [ . height( self . detentHeight) ] )
122123 }
124+ . ifApply ( UIDevice . current. userInterfaceIdiom != . phone, content: { v in
125+ v. background ( GeometryReader { geometry in
126+ Color . clear
127+ . onAppear {
128+ self . barItemFrame = geometry. frame ( in: . global)
129+ }
130+ . onChange ( of: geometry. frame ( in: . global) ) { newValue in
131+ self . barItemFrame = newValue
132+ }
133+ } )
134+ } )
123135 }
124136}
125137
@@ -132,6 +144,7 @@ struct PickerMenuItem: View {
132144 @State var detentHeight : CGFloat = ( ( UIDevice . current. userInterfaceIdiom == . phone || UIDevice . current. userInterfaceIdiom != . phone) ? 88 : 0 )
133145 let popoverWidth = 393.0
134146 @State var _keyboardHeight = 0.0
147+ @State var barItemFrame : CGRect = . zero
135148
136149 public init ( item: Binding < SortFilterItem . PickerItem > , onUpdate: @escaping ( ) -> Void ) {
137150 self . _item = item
@@ -163,7 +176,7 @@ struct PickerMenuItem: View {
163176 . onTapGesture {
164177 self . isSheetVisible. toggle ( )
165178 }
166- . popover ( isPresented: self . $isSheetVisible) {
179+ . popover ( isPresented: self . $isSheetVisible, arrowEdge : self . barItemFrame . arrowDirection ( ) ) {
167180 CancellableResettableDialogForm {
168181 SortFilterItemTitle ( title: self . item. name)
169182 } cancelAction: {
@@ -210,6 +223,17 @@ struct PickerMenuItem: View {
210223 }
211224 . presentationDetents ( [ . height( self . detentHeight) ] )
212225 }
226+ . ifApply ( UIDevice . current. userInterfaceIdiom != . phone, content: { v in
227+ v. background ( GeometryReader { geometry in
228+ Color . clear
229+ . onAppear {
230+ self . barItemFrame = geometry. frame ( in: . global)
231+ }
232+ . onChange ( of: geometry. frame ( in: . global) ) { newValue in
233+ self . barItemFrame = newValue
234+ }
235+ } )
236+ } )
213237 }
214238
215239 @ViewBuilder
@@ -245,7 +269,7 @@ struct PickerMenuItem: View {
245269 . onTapGesture {
246270 self . isSheetVisible. toggle ( )
247271 }
248- . popover ( isPresented: self . $isSheetVisible) {
272+ . popover ( isPresented: self . $isSheetVisible, arrowEdge : self . barItemFrame . arrowDirection ( ) ) {
249273 CancellableResettableDialogNavigationForm {
250274 SortFilterItemTitle ( title: self . item. name)
251275 } cancelAction: {
@@ -276,7 +300,7 @@ struct PickerMenuItem: View {
276300 } )
277301 . buttonStyle ( ApplyButtonStyle ( ) )
278302 } components: {
279- SearchListPickerItem ( value: self . $item. workingValue, valueOptions: self . item. valueOptions, hint: nil , allowsMultipleSelection: self . item. allowsMultipleSelection, allowsEmptySelection: self . item. allowsEmptySelection, isSearchBarHidden: self . item. isSearchBarHidden, disableListEntriesSection: self . item. disableListEntriesSection, allowsDisplaySelectionCount: self . item. allowsDisplaySelectionCount) { index in
303+ SearchListPickerItem ( value: self . $item. workingValue, valueOptions: self . item. valueOptions, hint: nil , allowsMultipleSelection: self . item. allowsMultipleSelection, allowsEmptySelection: self . item. allowsEmptySelection, isSearchBarHidden: self . item. isSearchBarHidden, disableListEntriesSection: self . item. disableListEntriesSection, allowsDisplaySelectionCount: self . item. allowsDisplaySelectionCount, barItemFrame : self . barItemFrame ) { index in
280304 self . item. onTap ( option: self . item. valueOptions [ index] )
281305 } selectAll: { isAll in
282306 self . item. selectAll ( isAll)
@@ -297,6 +321,17 @@ struct PickerMenuItem: View {
297321 . frame ( height: UIDevice . current. userInterfaceIdiom != . phone ? self . calculateDetentHeight ( ) : nil )
298322 . presentationDetents ( [ . height( self . calculateDetentHeight ( ) ) , . medium, . large] )
299323 }
324+ . ifApply ( UIDevice . current. userInterfaceIdiom != . phone, content: { v in
325+ v. background ( GeometryReader { geometry in
326+ Color . clear
327+ . onAppear {
328+ self . barItemFrame = geometry. frame ( in: . global)
329+ }
330+ . onChange ( of: geometry. frame ( in: . global) ) { newValue in
331+ self . barItemFrame = newValue
332+ }
333+ } )
334+ } )
300335 }
301336
302337 private func calculateDetentHeight( ) -> CGFloat {
@@ -369,6 +404,7 @@ struct DateTimeMenuItem: View {
369404 @State private var isSheetVisible : Bool = false
370405
371406 @State var detentHeight : CGFloat = 0
407+ @State var barItemFrame : CGRect = . zero
372408
373409 var onUpdate : ( ) -> Void
374410
@@ -388,7 +424,7 @@ struct DateTimeMenuItem: View {
388424 . onTapGesture {
389425 self . isSheetVisible. toggle ( )
390426 }
391- . popover ( isPresented: self . $isSheetVisible) {
427+ . popover ( isPresented: self . $isSheetVisible, arrowEdge : self . barItemFrame . arrowDirection ( ) ) {
392428 CancellableResettableDialogForm {
393429 SortFilterItemTitle ( title: self . item. name)
394430 } cancelAction: {
@@ -448,6 +484,17 @@ struct DateTimeMenuItem: View {
448484 }
449485 . presentationDetents ( [ . height( self . detentHeight) ] )
450486 }
487+ . ifApply ( UIDevice . current. userInterfaceIdiom != . phone, content: { v in
488+ v. background ( GeometryReader { geometry in
489+ Color . clear
490+ . onAppear {
491+ self . barItemFrame = geometry. frame ( in: . global)
492+ }
493+ . onChange ( of: geometry. frame ( in: . global) ) { newValue in
494+ self . barItemFrame = newValue
495+ }
496+ } )
497+ } )
451498 }
452499}
453500
@@ -512,6 +559,7 @@ struct StepperMenuItem: View {
512559 @State var isSheetVisible = false
513560
514561 @State var detentHeight : CGFloat = 0
562+ @State var barItemFrame : CGRect = . zero
515563
516564 var onUpdate : ( ) -> Void
517565
@@ -527,7 +575,7 @@ struct StepperMenuItem: View {
527575 . onTapGesture {
528576 self . isSheetVisible. toggle ( )
529577 }
530- . popover ( isPresented: self . $isSheetVisible) {
578+ . popover ( isPresented: self . $isSheetVisible, arrowEdge : self . barItemFrame . arrowDirection ( ) ) {
531579 CancellableResettableDialogForm {
532580 SortFilterItemTitle ( title: self . item. name)
533581 } cancelAction: {
@@ -598,6 +646,17 @@ struct StepperMenuItem: View {
598646 }
599647 . presentationDetents ( [ . height( self . detentHeight) ] )
600648 }
649+ . ifApply ( UIDevice . current. userInterfaceIdiom != . phone, content: { v in
650+ v. background ( GeometryReader { geometry in
651+ Color . clear
652+ . onAppear {
653+ self . barItemFrame = geometry. frame ( in: . global)
654+ }
655+ . onChange ( of: geometry. frame ( in: . global) ) { newValue in
656+ self . barItemFrame = newValue
657+ }
658+ } )
659+ } )
601660 }
602661}
603662
@@ -668,6 +727,18 @@ struct FullCFGMenuItem: View {
668727 }
669728}
670729
730+ extension CGRect {
731+ /// Popover arrowEdge depends on bar item position,
732+ /// only return `.top` or `.bottom` in this case
733+ /// - Returns: Edge
734+ func arrowDirection( ) -> Edge {
735+ if self . minY > Screen . bounds. size. height / 2 {
736+ return . bottom
737+ }
738+ return . top
739+ }
740+ }
741+
671742#Preview {
672743 VStack {
673744 Spacer ( )
0 commit comments