@onekeyfe/react-native-native-sheet 3.0.132 → 3.0.134

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.
@@ -17,6 +17,7 @@ import android.view.ViewTreeObserver
17
17
  import android.view.Window
18
18
  import android.view.WindowManager
19
19
  import android.view.animation.AccelerateDecelerateInterpolator
20
+ import android.view.inputmethod.InputMethodManager
20
21
  import android.widget.FrameLayout
21
22
  import androidx.core.view.ViewCompat
22
23
  import androidx.core.view.WindowCompat
@@ -257,6 +258,9 @@ class NativeSheetView(
257
258
  private var navigationBarBackgroundView: View? = null
258
259
  private var navigationBarBackgroundColor = Color.TRANSPARENT
259
260
  private var preImeBottomSheetBottomPx: Int? = null
261
+ private var pendingImeTarget: WeakReference<View>? = null
262
+ private var windowFocusListener: ViewTreeObserver.OnWindowFocusChangeListener? = null
263
+ private var userDrivenSheetSlide = false
260
264
 
261
265
  init {
262
266
  visibility = INVISIBLE
@@ -321,7 +325,12 @@ class NativeSheetView(
321
325
  background = createSheetBackground(resolvedSheetBackgroundColor)
322
326
  clipToOutline = true
323
327
  }
324
- contentChild?.let { attachChild(content, it, 0) }
328
+ contentChild?.let { child ->
329
+ pendingImeTarget = child.findFocus()
330
+ ?.takeIf { it.onCheckIsTextEditor() }
331
+ ?.let(::WeakReference)
332
+ attachChild(content, child, 0)
333
+ }
325
334
  if (showHandle) content.addView(createHandle(), createHandleLayoutParams())
326
335
 
327
336
  pendingDismissReason = "system"
@@ -381,6 +390,7 @@ class NativeSheetView(
381
390
  setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
382
391
  configureEdgeToEdgeWindow(this)
383
392
  }
393
+ restorePendingImeFocus(sheetDialog)
384
394
  animateDimAmount(
385
395
  sheetDialog,
386
396
  dimAmount.coerceIn(0.0, 1.0).toFloat(),
@@ -477,13 +487,25 @@ class NativeSheetView(
477
487
  state = BottomSheetBehavior.STATE_EXPANDED
478
488
  addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
479
489
  override fun onStateChanged(bottomSheet: View, newState: Int) {
480
- if (newState == BottomSheetBehavior.STATE_HIDDEN) {
481
- pendingDismissReason = "pan"
490
+ when (newState) {
491
+ BottomSheetBehavior.STATE_DRAGGING -> userDrivenSheetSlide = true
492
+ BottomSheetBehavior.STATE_EXPANDED -> {
493
+ if (userDrivenSheetSlide) {
494
+ sheetDialog.window?.setDimAmount(
495
+ dimAmount.coerceIn(0.0, 1.0).toFloat(),
496
+ )
497
+ }
498
+ userDrivenSheetSlide = false
499
+ }
500
+ BottomSheetBehavior.STATE_HIDDEN -> {
501
+ pendingDismissReason = "pan"
502
+ userDrivenSheetSlide = false
503
+ }
482
504
  }
483
505
  }
484
506
 
485
507
  override fun onSlide(bottomSheet: View, slideOffset: Float) {
486
- if (slideOffset < 1f) {
508
+ if (userDrivenSheetSlide && slideOffset < 1f) {
487
509
  dimAnimator?.cancel()
488
510
  sheetDialog.window?.setDimAmount(
489
511
  dimAmount.coerceIn(0.0, 1.0).toFloat() * slideOffset.coerceIn(0f, 1f),
@@ -764,6 +786,45 @@ class NativeSheetView(
764
786
  return true
765
787
  }
766
788
 
789
+ private fun restorePendingImeFocus(sheetDialog: BottomSheetDialog) {
790
+ val target = pendingImeTarget?.get() ?: return
791
+ val decorView = sheetDialog.window?.decorView ?: return
792
+ val showIme = {
793
+ if (dialog === sheetDialog && target.isAttachedToWindow) {
794
+ target.requestFocus()
795
+ target.post {
796
+ if (dialog === sheetDialog && target.hasFocus()) {
797
+ val inputMethodManager = reactContext.getSystemService(
798
+ android.content.Context.INPUT_METHOD_SERVICE,
799
+ ) as? InputMethodManager
800
+ inputMethodManager?.showSoftInput(target, InputMethodManager.SHOW_IMPLICIT)
801
+ }
802
+ }
803
+ }
804
+ clearPendingImeFocus(decorView)
805
+ }
806
+ if (decorView.hasWindowFocus()) {
807
+ showIme()
808
+ return
809
+ }
810
+ val listener = object : ViewTreeObserver.OnWindowFocusChangeListener {
811
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
812
+ if (hasFocus) showIme()
813
+ }
814
+ }
815
+ windowFocusListener = listener
816
+ decorView.viewTreeObserver.addOnWindowFocusChangeListener(listener)
817
+ }
818
+
819
+ private fun clearPendingImeFocus(decorView: View? = dialog?.window?.decorView) {
820
+ val listener = windowFocusListener
821
+ if (listener != null && decorView?.viewTreeObserver?.isAlive == true) {
822
+ decorView.viewTreeObserver.removeOnWindowFocusChangeListener(listener)
823
+ }
824
+ windowFocusListener = null
825
+ pendingImeTarget = null
826
+ }
827
+
767
828
  internal fun dismissDialogInternal(
768
829
  reason: String,
769
830
  animated: Boolean,
@@ -826,6 +887,7 @@ class NativeSheetView(
826
887
 
827
888
  private fun handleDialogDismissed() {
828
889
  val child = contentChild
890
+ clearPendingImeFocus()
829
891
  clearWindowInsetsObservation()
830
892
  navigationBarBackgroundView?.let { view ->
831
893
  (view.parent as? ViewGroup)?.removeView(view)
@@ -843,6 +905,7 @@ class NativeSheetView(
843
905
  extendsIntoNavigationBar = false
844
906
  navigationBarBackgroundColor = Color.TRANSPARENT
845
907
  preImeBottomSheetBottomPx = null
908
+ userDrivenSheetSlide = false
846
909
  dimAnimator?.cancel()
847
910
  dimAnimator = null
848
911
  heightAnimator?.cancel()
@@ -304,6 +304,7 @@ private final class NativeSheetViewController: UIViewController,
304
304
  private let showHandleValue: Bool
305
305
  private let dismissOnBackdropPressValue: Bool
306
306
  private let dimAmountValue: CGFloat
307
+ private let backgroundView = UIView()
307
308
  private var backdropTap: UITapGestureRecognizer?
308
309
  private var dimmingView: UIView?
309
310
  private var heightAnimator: UIViewPropertyAnimator?
@@ -340,10 +341,18 @@ private final class NativeSheetViewController: UIViewController,
340
341
  }
341
342
 
342
343
  override func loadView() {
343
- view = UIView()
344
- view.backgroundColor = backgroundColorValue
345
- view.clipsToBounds = true
346
- host.attachTouchHandler(to: view)
344
+ let rootView = UIView()
345
+ rootView.backgroundColor = backgroundColorValue
346
+ rootView.clipsToBounds = true
347
+ if #available(iOS 26.0, *) {
348
+ backgroundView.frame = rootView.bounds
349
+ backgroundView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
350
+ backgroundView.backgroundColor = backgroundColorValue
351
+ backgroundView.isUserInteractionEnabled = false
352
+ rootView.addSubview(backgroundView)
353
+ }
354
+ view = rootView
355
+ host.attachTouchHandler(to: rootView)
347
356
  }
348
357
 
349
358
  deinit {
@@ -358,11 +367,15 @@ private final class NativeSheetViewController: UIViewController,
358
367
  super.viewDidLoad()
359
368
  host.moveContent(to: view)
360
369
  guard let sheet = sheetPresentationController else { return }
361
- sheet.detents = [
362
- .custom(identifier: detentIdentifier) { [weak self] context in
363
- min(max(self?.targetHeight ?? 1, 1), context.maximumDetentValue)
364
- },
365
- ]
370
+ let detent = UISheetPresentationController.Detent.custom(
371
+ identifier: detentIdentifier
372
+ ) { [weak self] context in
373
+ min(max(self?.targetHeight ?? 1, 1), context.maximumDetentValue)
374
+ }
375
+ if #available(iOS 26.1, *) {
376
+ detent.backgroundEffect = UIColorEffect(color: backgroundColorValue)
377
+ }
378
+ sheet.detents = [detent]
366
379
  sheet.selectedDetentIdentifier = detentIdentifier
367
380
  sheet.largestUndimmedDetentIdentifier = detentIdentifier
368
381
  sheet.prefersGrabberVisible = showHandleValue
@@ -466,6 +479,11 @@ private final class NativeSheetViewController: UIViewController,
466
479
  override func viewDidLayoutSubviews() {
467
480
  super.viewDidLayoutSubviews()
468
481
  removePresentationShadow()
482
+ if #available(iOS 26.0, *) {
483
+ DispatchQueue.main.async { [weak self] in
484
+ self?.removePresentationShadow()
485
+ }
486
+ }
469
487
  host.layoutPresentedContent(in: view.bounds)
470
488
  }
471
489
 
@@ -527,6 +545,10 @@ private final class NativeSheetViewController: UIViewController,
527
545
  private func clearShadow(on shadowView: UIView) {
528
546
  CATransaction.begin()
529
547
  CATransaction.setDisableActions(true)
548
+ if #available(iOS 26.0, *),
549
+ NSStringFromClass(type(of: shadowView)).contains("UIDropShadowView") {
550
+ compensateForPresentationScale(in: shadowView)
551
+ }
530
552
  shadowView.layer.shadowOpacity = 0
531
553
  shadowView.layer.shadowRadius = 0
532
554
  shadowView.layer.shadowColor = UIColor.clear.cgColor
@@ -534,6 +556,21 @@ private final class NativeSheetViewController: UIViewController,
534
556
  CATransaction.commit()
535
557
  }
536
558
 
559
+ @available(iOS 26.0, *)
560
+ private func compensateForPresentationScale(in shadowView: UIView) {
561
+ guard var surfaceView = view else { return }
562
+ while let parent = surfaceView.superview, parent !== shadowView {
563
+ surfaceView = parent
564
+ }
565
+ guard surfaceView.superview === shadowView else { return }
566
+ let transform = shadowView.transform
567
+ guard abs(transform.a) > 0.001, abs(transform.d) > 0.001 else { return }
568
+ surfaceView.transform = CGAffineTransform(
569
+ scaleX: 1 / transform.a,
570
+ y: 1 / transform.d
571
+ )
572
+ }
573
+
537
574
  private func startSuppressingPresentationShadow() {
538
575
  shadowSuppressionDisplayLink?.invalidate()
539
576
  removePresentationShadow()
@@ -672,7 +709,7 @@ private final class NativeSheetContentWrapperView: UIView {
672
709
  if let controller = presentedController {
673
710
  moveContent(to: controller.view)
674
711
  } else {
675
- moveContent(to: self)
712
+ stageContent()
676
713
  }
677
714
  }
678
715
 
@@ -749,7 +786,7 @@ private final class NativeSheetContentWrapperView: UIView {
749
786
  fileprivate func finishDismiss(reason: String) {
750
787
  if let child = contentChild {
751
788
  child.autoresizingMask = []
752
- moveContent(to: self)
789
+ stageContent()
753
790
  }
754
791
  let hadController = presentedController != nil
755
792
  presentedController = nil
@@ -773,6 +810,16 @@ private final class NativeSheetContentWrapperView: UIView {
773
810
  contentWrapperView.frame = parent.bounds
774
811
  }
775
812
 
813
+ private func stageContent() {
814
+ if #available(iOS 26.0, *) {
815
+ contentWrapperView.removeFromSuperview()
816
+ contentWrapperView.frame = bounds
817
+ contentWrapperView.layoutIfNeeded()
818
+ } else {
819
+ moveContent(to: self)
820
+ }
821
+ }
822
+
776
823
  fileprivate func layoutPresentedContent(in bounds: CGRect) {
777
824
  contentWrapperView.frame = bounds
778
825
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-native-sheet",
3
- "version": "3.0.132",
3
+ "version": "3.0.134",
4
4
  "description": "Native bottom sheet host for arbitrary React Native content",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/module/index.js",