@terreno/ui 0.14.0 → 0.14.2

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 (98) hide show
  1. package/dist/ActionSheet.d.ts +1 -1
  2. package/dist/ActionSheet.js +17 -29
  3. package/dist/ActionSheet.js.map +1 -1
  4. package/dist/Common.d.ts +8 -2
  5. package/dist/Common.js +4 -4
  6. package/dist/Common.js.map +1 -1
  7. package/dist/ConsentFormScreen.js +3 -3
  8. package/dist/ConsentFormScreen.js.map +1 -1
  9. package/dist/DateUtilities.d.ts +25 -25
  10. package/dist/DateUtilities.js +31 -32
  11. package/dist/DateUtilities.js.map +1 -1
  12. package/dist/MarkdownView.js +20 -7
  13. package/dist/MarkdownView.js.map +1 -1
  14. package/dist/MediaQuery.d.ts +4 -4
  15. package/dist/MediaQuery.js +8 -8
  16. package/dist/MediaQuery.js.map +1 -1
  17. package/dist/Page.d.ts +1 -0
  18. package/dist/Page.js +6 -2
  19. package/dist/Page.js.map +1 -1
  20. package/dist/PickerSelect.d.ts +1 -1
  21. package/dist/PickerSelect.js +2 -2
  22. package/dist/PickerSelect.js.map +1 -1
  23. package/dist/TapToEdit.d.ts +1 -1
  24. package/dist/TapToEdit.js +2 -3
  25. package/dist/TapToEdit.js.map +1 -1
  26. package/dist/ToastNotifications.js +2 -2
  27. package/dist/ToastNotifications.js.map +1 -1
  28. package/dist/Tooltip.d.ts +24 -1
  29. package/dist/Tooltip.js +2 -2
  30. package/dist/Tooltip.js.map +1 -1
  31. package/dist/Unifier.d.ts +1 -1
  32. package/dist/Unifier.js +14 -11
  33. package/dist/Unifier.js.map +1 -1
  34. package/dist/Utilities.d.ts +8 -8
  35. package/dist/Utilities.js +12 -14
  36. package/dist/Utilities.js.map +1 -1
  37. package/dist/index.d.ts +1 -1
  38. package/dist/index.js +1 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/signUp/PasswordRequirements.js +3 -3
  41. package/dist/signUp/PasswordRequirements.js.map +1 -1
  42. package/dist/table/TableHeaderCell.js +1 -9
  43. package/dist/table/TableHeaderCell.js.map +1 -1
  44. package/dist/table/tableContext.d.ts +1 -1
  45. package/dist/table/tableContext.js +2 -2
  46. package/dist/table/tableContext.js.map +1 -1
  47. package/dist/useConsentHistory.d.ts +6 -1
  48. package/dist/useConsentHistory.js +2 -1
  49. package/dist/useConsentHistory.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/ActionSheet.test.tsx +554 -0
  52. package/src/ActionSheet.tsx +26 -39
  53. package/src/Banner.test.tsx +107 -1
  54. package/src/Common.ts +10 -4
  55. package/src/ConsentFormScreen.test.tsx +22 -0
  56. package/src/ConsentFormScreen.tsx +9 -3
  57. package/src/DataTable.test.tsx +393 -1
  58. package/src/DateTimeField.test.tsx +716 -2
  59. package/src/DateUtilities.tsx +37 -38
  60. package/src/HeightActionSheet.test.tsx +17 -1
  61. package/src/HeightField.test.tsx +141 -1
  62. package/src/HeightFieldDesktop.test.tsx +19 -0
  63. package/src/MarkdownView.test.tsx +28 -0
  64. package/src/MarkdownView.tsx +69 -7
  65. package/src/MediaQuery.ts +8 -8
  66. package/src/MobileAddressAutoComplete.test.tsx +26 -3
  67. package/src/Page.test.tsx +28 -0
  68. package/src/Page.tsx +17 -2
  69. package/src/PickerSelect.test.tsx +243 -0
  70. package/src/PickerSelect.tsx +3 -3
  71. package/src/SplitPage.test.tsx +299 -43
  72. package/src/TapToEdit.test.tsx +44 -0
  73. package/src/TapToEdit.tsx +2 -3
  74. package/src/ToastNotifications.test.tsx +1412 -0
  75. package/src/ToastNotifications.tsx +2 -2
  76. package/src/Tooltip.test.tsx +1294 -3
  77. package/src/Tooltip.tsx +2 -2
  78. package/src/Unifier.ts +14 -11
  79. package/src/Utilities.tsx +14 -16
  80. package/src/WebAddressAutocomplete.test.tsx +237 -0
  81. package/src/WebDropdownMenu.test.tsx +51 -2
  82. package/src/__snapshots__/Banner.test.tsx.snap +125 -0
  83. package/src/__snapshots__/DataTable.test.tsx.snap +366 -0
  84. package/src/__snapshots__/MarkdownView.test.tsx.snap +284 -74
  85. package/src/__snapshots__/SplitPage.test.tsx.snap +698 -46
  86. package/src/bunSetup.ts +0 -4
  87. package/src/index.tsx +1 -1
  88. package/src/login/LoginScreen.test.tsx +35 -1
  89. package/src/signUp/PasswordRequirements.tsx +9 -6
  90. package/src/signUp/__snapshots__/PasswordRequirements.test.tsx.snap +50 -2
  91. package/src/signUp/__snapshots__/SignUpScreen.test.tsx.snap +25 -1
  92. package/src/table/TableHeaderCell.tsx +8 -11
  93. package/src/table/TableRow.test.tsx +31 -1
  94. package/src/table/__snapshots__/TableHeaderCell.test.tsx.snap +2 -0
  95. package/src/table/tableContext.tsx +2 -2
  96. package/src/useConsentHistory.test.ts +20 -13
  97. package/src/useConsentHistory.ts +7 -2
  98. package/src/useStoredState.test.tsx +47 -0
@@ -334,4 +334,558 @@ describe("ActionSheet", () => {
334
334
  expect(result).toBeNull();
335
335
  });
336
336
  });
337
+
338
+ describe("measure", () => {
339
+ it("resolves with 20 when safeAreaViewRef has no measureInWindow", async () => {
340
+ const ref = createRef<ActionSheet>();
341
+ render(
342
+ <ThemeProvider>
343
+ <ActionSheet ref={ref}>
344
+ <Text>Content</Text>
345
+ </ActionSheet>
346
+ </ThemeProvider>
347
+ );
348
+ const result = await (ref.current as any).measure();
349
+ expect(result).toBe(20);
350
+ });
351
+
352
+ it("resolves with height from measureInWindow when available", async () => {
353
+ const ref = createRef<ActionSheet>();
354
+ render(
355
+ <ThemeProvider>
356
+ <ActionSheet ref={ref}>
357
+ <Text>Content</Text>
358
+ </ActionSheet>
359
+ </ThemeProvider>
360
+ );
361
+ (ref.current as any).safeAreaViewRef = {
362
+ current: {
363
+ measureInWindow: (_cb: any) => {
364
+ _cb(0, 0, 100, 44);
365
+ },
366
+ },
367
+ };
368
+ const result = await (ref.current as any).measure();
369
+ expect(result).toBe(44);
370
+ });
371
+
372
+ it("resolves with 20 when measureInWindow returns 0 height", async () => {
373
+ const ref = createRef<ActionSheet>();
374
+ render(
375
+ <ThemeProvider>
376
+ <ActionSheet ref={ref}>
377
+ <Text>Content</Text>
378
+ </ActionSheet>
379
+ </ThemeProvider>
380
+ );
381
+ (ref.current as any).safeAreaViewRef = {
382
+ current: {
383
+ measureInWindow: (_cb: any) => {
384
+ _cb(0, 0, 100, 0);
385
+ },
386
+ },
387
+ };
388
+ const result = await (ref.current as any).measure();
389
+ expect(result).toBe(20);
390
+ });
391
+ });
392
+
393
+ describe("_showModal", () => {
394
+ it("returns early when nativeEvent is missing", async () => {
395
+ const ref = createRef<ActionSheet>();
396
+ render(
397
+ <ThemeProvider>
398
+ <ActionSheet ref={ref}>
399
+ <Text>Content</Text>
400
+ </ActionSheet>
401
+ </ThemeProvider>
402
+ );
403
+ await (ref.current as any)._showModal({});
404
+ expect(ref.current).toBeTruthy();
405
+ });
406
+
407
+ it("processes layout event on first call and sets actionSheetHeight", async () => {
408
+ const ref = createRef<ActionSheet>();
409
+ render(
410
+ <ThemeProvider>
411
+ <ActionSheet animated={false} ref={ref}>
412
+ <Text>Content</Text>
413
+ </ActionSheet>
414
+ </ThemeProvider>
415
+ );
416
+ ref.current!.layoutHasCalled = false;
417
+ await (ref.current as any)._showModal({
418
+ nativeEvent: {layout: {height: 500, width: 400}},
419
+ });
420
+ expect((ref.current as any).actionSheetHeight).toBe(500);
421
+ expect(ref.current!.layoutHasCalled).toBe(true);
422
+ });
423
+
424
+ it("handles subsequent layout calls (layoutHasCalled=true)", async () => {
425
+ const ref = createRef<ActionSheet>();
426
+ render(
427
+ <ThemeProvider>
428
+ <ActionSheet ref={ref}>
429
+ <Text>Content</Text>
430
+ </ActionSheet>
431
+ </ThemeProvider>
432
+ );
433
+ ref.current!.layoutHasCalled = true;
434
+ (ref.current as any).actionSheetHeight = 400;
435
+ await (ref.current as any)._showModal({
436
+ nativeEvent: {layout: {height: 600, width: 400}},
437
+ });
438
+ expect((ref.current as any).actionSheetHeight).toBe(600);
439
+ });
440
+ });
441
+
442
+ describe("_openAnimation", () => {
443
+ it("runs spring animation when animated is true", () => {
444
+ const ref = createRef<ActionSheet>();
445
+ render(
446
+ <ThemeProvider>
447
+ <ActionSheet animated ref={ref}>
448
+ <Text>Content</Text>
449
+ </ActionSheet>
450
+ </ThemeProvider>
451
+ );
452
+ expect(() => (ref.current as any)._openAnimation(100)).not.toThrow();
453
+ });
454
+
455
+ it("sets opacity directly when animated is false", () => {
456
+ const ref = createRef<ActionSheet>();
457
+ render(
458
+ <ThemeProvider>
459
+ <ActionSheet animated={false} ref={ref}>
460
+ <Text>Content</Text>
461
+ </ActionSheet>
462
+ </ThemeProvider>
463
+ );
464
+ expect(() => (ref.current as any)._openAnimation(100)).not.toThrow();
465
+ });
466
+ });
467
+
468
+ describe("_onScrollBeginDrag", () => {
469
+ it("stores the scroll position in prevScroll", async () => {
470
+ const ref = createRef<ActionSheet>();
471
+ render(
472
+ <ThemeProvider>
473
+ <ActionSheet ref={ref}>
474
+ <Text>Content</Text>
475
+ </ActionSheet>
476
+ </ThemeProvider>
477
+ );
478
+ await (ref.current as any)._onScrollBeginDrag({
479
+ nativeEvent: {contentOffset: {y: 42}},
480
+ });
481
+ expect((ref.current as any).prevScroll).toBe(42);
482
+ });
483
+ });
484
+
485
+ describe("_applyHeightLimiter", () => {
486
+ it("clamps actionSheetHeight to deviceHeight", () => {
487
+ const ref = createRef<ActionSheet>();
488
+ render(
489
+ <ThemeProvider>
490
+ <ActionSheet ref={ref}>
491
+ <Text>Content</Text>
492
+ </ActionSheet>
493
+ </ThemeProvider>
494
+ );
495
+ (ref.current as any).actionSheetHeight = 99999;
496
+ (ref.current as any)._applyHeightLimiter();
497
+ expect((ref.current as any).actionSheetHeight).toBeLessThanOrEqual(
498
+ ref.current!.state.deviceHeight
499
+ );
500
+ });
501
+
502
+ it("does not change actionSheetHeight when smaller than deviceHeight", () => {
503
+ const ref = createRef<ActionSheet>();
504
+ render(
505
+ <ThemeProvider>
506
+ <ActionSheet ref={ref}>
507
+ <Text>Content</Text>
508
+ </ActionSheet>
509
+ </ThemeProvider>
510
+ );
511
+ (ref.current as any).actionSheetHeight = 100;
512
+ (ref.current as any)._applyHeightLimiter();
513
+ expect((ref.current as any).actionSheetHeight).toBe(100);
514
+ });
515
+ });
516
+
517
+ describe("_onScrollEnd", () => {
518
+ it("handles upward scroll past springOffset threshold", async () => {
519
+ const ref = createRef<ActionSheet>();
520
+ render(
521
+ <ThemeProvider>
522
+ <ActionSheet ref={ref} springOffset={50}>
523
+ <Text>Content</Text>
524
+ </ActionSheet>
525
+ </ThemeProvider>
526
+ );
527
+ (ref.current as any).prevScroll = 100;
528
+ (ref.current as any).actionSheetHeight = 500;
529
+ (ref.current as any).isRecoiling = false;
530
+ await (ref.current as any)._onScrollEnd({
531
+ nativeEvent: {contentOffset: {y: 200}},
532
+ });
533
+ expect(ref.current).toBeTruthy();
534
+ });
535
+
536
+ it("returns early when isRecoiling is true", async () => {
537
+ const ref = createRef<ActionSheet>();
538
+ render(
539
+ <ThemeProvider>
540
+ <ActionSheet ref={ref}>
541
+ <Text>Content</Text>
542
+ </ActionSheet>
543
+ </ThemeProvider>
544
+ );
545
+ (ref.current as any).isRecoiling = true;
546
+ await (ref.current as any)._onScrollEnd({
547
+ nativeEvent: {contentOffset: {y: 50}},
548
+ });
549
+ expect(ref.current).toBeTruthy();
550
+ });
551
+
552
+ it("handles downward scroll past springOffset (hides modal)", async () => {
553
+ const ref = createRef<ActionSheet>();
554
+ render(
555
+ <ThemeProvider>
556
+ <ActionSheet ref={ref} springOffset={10}>
557
+ <Text>Content</Text>
558
+ </ActionSheet>
559
+ </ThemeProvider>
560
+ );
561
+ (ref.current as any).prevScroll = 200;
562
+ (ref.current as any).isRecoiling = false;
563
+ await (ref.current as any)._onScrollEnd({
564
+ nativeEvent: {contentOffset: {y: 50}},
565
+ });
566
+ expect(ref.current).toBeTruthy();
567
+ });
568
+
569
+ it("handles small downward scroll (recoils to previous position)", async () => {
570
+ const ref = createRef<ActionSheet>();
571
+ render(
572
+ <ThemeProvider>
573
+ <ActionSheet ref={ref} springOffset={200}>
574
+ <Text>Content</Text>
575
+ </ActionSheet>
576
+ </ThemeProvider>
577
+ );
578
+ (ref.current as any).prevScroll = 100;
579
+ (ref.current as any).isRecoiling = false;
580
+ await (ref.current as any)._onScrollEnd({
581
+ nativeEvent: {contentOffset: {y: 95}},
582
+ });
583
+ expect(ref.current).toBeTruthy();
584
+ });
585
+
586
+ it("handles small upward scroll (returns to prev position)", async () => {
587
+ const ref = createRef<ActionSheet>();
588
+ render(
589
+ <ThemeProvider>
590
+ <ActionSheet ref={ref} springOffset={200}>
591
+ <Text>Content</Text>
592
+ </ActionSheet>
593
+ </ThemeProvider>
594
+ );
595
+ (ref.current as any).prevScroll = 100;
596
+ (ref.current as any).actionSheetHeight = 500;
597
+ (ref.current as any).isRecoiling = false;
598
+ await (ref.current as any)._onScrollEnd({
599
+ nativeEvent: {contentOffset: {y: 110}},
600
+ });
601
+ expect(ref.current).toBeTruthy();
602
+ });
603
+ });
604
+
605
+ describe("_onKeyboardShow", () => {
606
+ it("sets keyboard state to true and handles no focused field", () => {
607
+ const ref = createRef<ActionSheet>();
608
+ render(
609
+ <ThemeProvider>
610
+ <ActionSheet ref={ref}>
611
+ <Text>Content</Text>
612
+ </ActionSheet>
613
+ </ThemeProvider>
614
+ );
615
+ const {TextInput: MockTextInput} = require("react-native");
616
+ const origState = MockTextInput.State;
617
+ MockTextInput.State = {
618
+ currentlyFocusedField: () => null,
619
+ };
620
+ act(() => {
621
+ (ref.current as any)._onKeyboardShow({
622
+ endCoordinates: {height: 300, screenX: 0, screenY: 500, width: 400},
623
+ });
624
+ });
625
+ expect(ref.current!.state.keyboard).toBe(true);
626
+ MockTextInput.State = origState;
627
+ });
628
+
629
+ it("handles keyboard show with focused field", () => {
630
+ const ref = createRef<ActionSheet>();
631
+ render(
632
+ <ThemeProvider>
633
+ <ActionSheet ref={ref}>
634
+ <Text>Content</Text>
635
+ </ActionSheet>
636
+ </ThemeProvider>
637
+ );
638
+ const {TextInput: MockTextInput, UIManager: MockUIManager} = require("react-native");
639
+ const origState = MockTextInput.State;
640
+ const origMeasure = MockUIManager.measure;
641
+ MockTextInput.State = {
642
+ currentlyFocusedField: () => 42,
643
+ };
644
+ MockUIManager.measure = (_node: any, cb: any) => {
645
+ cb(0, 0, 100, 40, 0, 400);
646
+ };
647
+ act(() => {
648
+ (ref.current as any)._onKeyboardShow({
649
+ endCoordinates: {height: 300, screenX: 0, screenY: 500, width: 400},
650
+ });
651
+ });
652
+ expect(ref.current!.state.keyboard).toBe(true);
653
+ MockTextInput.State = origState;
654
+ MockUIManager.measure = origMeasure;
655
+ });
656
+
657
+ it("handles keyboard show with enough gap (no animation needed)", () => {
658
+ const ref = createRef<ActionSheet>();
659
+ render(
660
+ <ThemeProvider>
661
+ <ActionSheet ref={ref}>
662
+ <Text>Content</Text>
663
+ </ActionSheet>
664
+ </ThemeProvider>
665
+ );
666
+ const {TextInput: MockTextInput, UIManager: MockUIManager} = require("react-native");
667
+ const origState = MockTextInput.State;
668
+ const origMeasure = MockUIManager.measure;
669
+ MockTextInput.State = {
670
+ currentlyFocusedField: () => 42,
671
+ };
672
+ MockUIManager.measure = (_node: any, cb: any) => {
673
+ cb(0, 0, 100, 40, 0, 100);
674
+ };
675
+ act(() => {
676
+ (ref.current as any)._onKeyboardShow({
677
+ endCoordinates: {height: 100, screenX: 0, screenY: 500, width: 400},
678
+ });
679
+ });
680
+ expect(ref.current!.state.keyboard).toBe(true);
681
+ MockTextInput.State = origState;
682
+ MockUIManager.measure = origMeasure;
683
+ });
684
+ });
685
+
686
+ describe("_onKeyboardHide", () => {
687
+ it("sets keyboard state to false and animates", () => {
688
+ const ref = createRef<ActionSheet>();
689
+ render(
690
+ <ThemeProvider>
691
+ <ActionSheet ref={ref}>
692
+ <Text>Content</Text>
693
+ </ActionSheet>
694
+ </ThemeProvider>
695
+ );
696
+ act(() => {
697
+ (ref.current as any)._onKeyboardHide();
698
+ });
699
+ expect(ref.current!.state.keyboard).toBe(false);
700
+ });
701
+ });
702
+
703
+ describe("handleChildScrollEnd", () => {
704
+ it("returns early when offsetY > prevScroll", async () => {
705
+ const ref = createRef<ActionSheet>();
706
+ render(
707
+ <ThemeProvider>
708
+ <ActionSheet ref={ref}>
709
+ <Text>Content</Text>
710
+ </ActionSheet>
711
+ </ThemeProvider>
712
+ );
713
+ (ref.current as any).offsetY = 200;
714
+ (ref.current as any).prevScroll = 100;
715
+ await (ref.current as any).handleChildScrollEnd();
716
+ expect(ref.current).toBeTruthy();
717
+ });
718
+
719
+ it("hides modal when scroll offset is far from initial position", async () => {
720
+ const ref = createRef<ActionSheet>();
721
+ render(
722
+ <ThemeProvider>
723
+ <ActionSheet ref={ref} springOffset={10}>
724
+ <Text>Content</Text>
725
+ </ActionSheet>
726
+ </ThemeProvider>
727
+ );
728
+ (ref.current as any).offsetY = 0;
729
+ (ref.current as any).prevScroll = 200;
730
+ (ref.current as any).actionSheetHeight = 500;
731
+ await (ref.current as any).handleChildScrollEnd();
732
+ expect(ref.current).toBeTruthy();
733
+ });
734
+
735
+ it("recoils to prevScroll when within springOffset range", async () => {
736
+ const ref = createRef<ActionSheet>();
737
+ render(
738
+ <ThemeProvider>
739
+ <ActionSheet ref={ref} springOffset={200}>
740
+ <Text>Content</Text>
741
+ </ActionSheet>
742
+ </ThemeProvider>
743
+ );
744
+ (ref.current as any).offsetY = 90;
745
+ (ref.current as any).prevScroll = 100;
746
+ await (ref.current as any).handleChildScrollEnd();
747
+ expect(ref.current).toBeTruthy();
748
+ });
749
+
750
+ it("scrolls back to initial position when close to it", async () => {
751
+ const ref = createRef<ActionSheet>();
752
+ render(
753
+ <ThemeProvider>
754
+ <ActionSheet gestureEnabled initialOffsetFromBottom={1} ref={ref} springOffset={10}>
755
+ <Text>Content</Text>
756
+ </ActionSheet>
757
+ </ThemeProvider>
758
+ );
759
+ (ref.current as any).offsetY = 50;
760
+ (ref.current as any).prevScroll = 200;
761
+ (ref.current as any).actionSheetHeight = 200;
762
+ await (ref.current as any).handleChildScrollEnd();
763
+ expect(ref.current).toBeTruthy();
764
+ });
765
+ });
766
+
767
+ describe("componentWillUnmount", () => {
768
+ it("removes keyboard listeners on unmount", () => {
769
+ const ref = createRef<ActionSheet>();
770
+ const {unmount} = render(
771
+ <ThemeProvider>
772
+ <ActionSheet ref={ref}>
773
+ <Text>Content</Text>
774
+ </ActionSheet>
775
+ </ThemeProvider>
776
+ );
777
+ expect(() => unmount()).not.toThrow();
778
+ });
779
+ });
780
+
781
+ describe("_onDeviceLayout", () => {
782
+ it("clears existing timeout before scheduling new one", () => {
783
+ const ref = createRef<ActionSheet>();
784
+ render(
785
+ <ThemeProvider>
786
+ <ActionSheet ref={ref}>
787
+ <Text>Content</Text>
788
+ </ActionSheet>
789
+ </ThemeProvider>
790
+ );
791
+ const existingTimeout = setTimeout(() => {}, 1000);
792
+ (ref.current as any).timeout = existingTimeout;
793
+ (ref.current as any)._onDeviceLayout({
794
+ nativeEvent: {layout: {height: 812, width: 375}},
795
+ });
796
+ const newTimeout = (ref.current as any).timeout;
797
+ expect(newTimeout).not.toBe(existingTimeout);
798
+ clearTimeout(newTimeout);
799
+ });
800
+ });
801
+
802
+ describe("getInitialScrollPosition", () => {
803
+ it("returns a scroll position with gestureEnabled", () => {
804
+ const ref = createRef<ActionSheet>();
805
+ render(
806
+ <ThemeProvider>
807
+ <ActionSheet gestureEnabled initialOffsetFromBottom={0.5} ref={ref}>
808
+ <Text>Content</Text>
809
+ </ActionSheet>
810
+ </ThemeProvider>
811
+ );
812
+ (ref.current as any).actionSheetHeight = 500;
813
+ const pos = (ref.current as any).getInitialScrollPosition();
814
+ expect(typeof pos).toBe("number");
815
+ });
816
+
817
+ it("returns a scroll position without gestureEnabled", () => {
818
+ const ref = createRef<ActionSheet>();
819
+ render(
820
+ <ThemeProvider>
821
+ <ActionSheet gestureEnabled={false} ref={ref}>
822
+ <Text>Content</Text>
823
+ </ActionSheet>
824
+ </ThemeProvider>
825
+ );
826
+ (ref.current as any).actionSheetHeight = 500;
827
+ const pos = (ref.current as any).getInitialScrollPosition();
828
+ expect(typeof pos).toBe("number");
829
+ });
830
+ });
831
+
832
+ describe("_hideAnimation with closable=false", () => {
833
+ it("snaps to bottomOffset when closable=false and bottomOffset>0", async () => {
834
+ const ref = createRef<ActionSheet>();
835
+ render(
836
+ <ThemeProvider>
837
+ <ActionSheet bottomOffset={50} closable={false} closeAnimationDuration={1} ref={ref}>
838
+ <Text>Content</Text>
839
+ </ActionSheet>
840
+ </ThemeProvider>
841
+ );
842
+ act(() => {
843
+ ref.current?.show();
844
+ });
845
+ (ref.current as any).isClosing = false;
846
+ act(() => {
847
+ (ref.current as any)._hideAnimation();
848
+ });
849
+ await act(async () => {
850
+ await new Promise((r) => setTimeout(r, 50));
851
+ });
852
+ expect(ref.current).toBeTruthy();
853
+ });
854
+
855
+ it("scrolls to initialOffset when closable=false and bottomOffset<=0", async () => {
856
+ const ref = createRef<ActionSheet>();
857
+ render(
858
+ <ThemeProvider>
859
+ <ActionSheet closable={false} closeAnimationDuration={1} ref={ref}>
860
+ <Text>Content</Text>
861
+ </ActionSheet>
862
+ </ThemeProvider>
863
+ );
864
+ act(() => {
865
+ ref.current?.show();
866
+ });
867
+ (ref.current as any).isClosing = false;
868
+ act(() => {
869
+ (ref.current as any)._hideAnimation();
870
+ });
871
+ await act(async () => {
872
+ await new Promise((r) => setTimeout(r, 50));
873
+ });
874
+ expect(ref.current).toBeTruthy();
875
+ });
876
+ });
877
+
878
+ describe("_onScrollBegin", () => {
879
+ it("does not throw", async () => {
880
+ const ref = createRef<ActionSheet>();
881
+ render(
882
+ <ThemeProvider>
883
+ <ActionSheet ref={ref}>
884
+ <Text>Content</Text>
885
+ </ActionSheet>
886
+ </ThemeProvider>
887
+ );
888
+ await expect((ref.current as any)._onScrollBegin()).resolves.toBeUndefined();
889
+ });
890
+ });
337
891
  });
@@ -56,7 +56,7 @@ export const styles = StyleSheet.create({
56
56
  },
57
57
  });
58
58
 
59
- export function getDeviceHeight(statusBarTranslucent: boolean | undefined): number {
59
+ export const getDeviceHeight = (statusBarTranslucent: boolean | undefined): number => {
60
60
  const height = Dimensions.get("window").height;
61
61
 
62
62
  if (Platform.OS === "android" && !statusBarTranslucent) {
@@ -64,7 +64,7 @@ export function getDeviceHeight(statusBarTranslucent: boolean | undefined): numb
64
64
  }
65
65
 
66
66
  return height;
67
- }
67
+ };
68
68
 
69
69
  export const getElevation = (elevation?: number) => {
70
70
  if (!elevation) {
@@ -580,48 +580,35 @@ export class ActionSheet extends Component<Props, State, unknown> {
580
580
  this.setState({
581
581
  keyboard: true,
582
582
  });
583
- const ReactNativeVersion = require("react-native/Libraries/Core/ReactNativeVersion");
584
-
585
- let v = ReactNativeVersion.version.major + ReactNativeVersion.version.minor;
586
- v = parseInt(v, 10);
587
583
 
588
- if (v >= 63 || Platform.OS === "ios") {
589
- const keyboardHeight = event.endCoordinates.height;
590
- const {height: windowHeight} = Dimensions.get("window");
584
+ const keyboardHeight = event.endCoordinates.height;
585
+ const {height: windowHeight} = Dimensions.get("window");
591
586
 
592
- const currentlyFocusedField = TextInput.State.currentlyFocusedField
593
- ? findNodeHandle(TextInput.State.currentlyFocusedField())
594
- : TextInput.State.currentlyFocusedField();
587
+ const currentlyFocusedField = TextInput.State.currentlyFocusedField
588
+ ? findNodeHandle(TextInput.State.currentlyFocusedField())
589
+ : TextInput.State.currentlyFocusedField();
595
590
 
596
- if (!currentlyFocusedField) {
597
- return;
598
- }
591
+ if (!currentlyFocusedField) {
592
+ return;
593
+ }
599
594
 
600
- UIManager.measure(
601
- currentlyFocusedField,
602
- (_originX, _originY, _width, height, _pageX, pageY) => {
603
- const fieldHeight = height;
604
- const gap = windowHeight - keyboardHeight - (pageY + fieldHeight);
605
- if (gap >= 0) {
606
- return;
607
- }
608
- const toValue =
609
- this.props.keyboardMode === "position" ? -(keyboardHeight + 15) : gap - 10;
610
-
611
- Animated.timing(this.transformValue, {
612
- duration: 250,
613
- toValue,
614
- useNativeDriver: true,
615
- }).start();
595
+ UIManager.measure(
596
+ currentlyFocusedField,
597
+ (_originX, _originY, _width, height, _pageX, pageY) => {
598
+ const fieldHeight = height;
599
+ const gap = windowHeight - keyboardHeight - (pageY + fieldHeight);
600
+ if (gap >= 0) {
601
+ return;
616
602
  }
617
- );
618
- } else {
619
- Animated.timing(this.transformValue, {
620
- duration: 250,
621
- toValue: -10,
622
- useNativeDriver: true,
623
- }).start();
624
- }
603
+ const toValue = this.props.keyboardMode === "position" ? -(keyboardHeight + 15) : gap - 10;
604
+
605
+ Animated.timing(this.transformValue, {
606
+ duration: 250,
607
+ toValue,
608
+ useNativeDriver: true,
609
+ }).start();
610
+ }
611
+ );
625
612
  };
626
613
 
627
614
  /**