Skip to content

Commit d5330f1

Browse files
committed
Removing react-native-safe-area-view, upgrading dev dependencies, adding displayAreaInset prop
1 parent a11d1b9 commit d5330f1

10 files changed

+3349
-3664
lines changed

README.md

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The `<Popover>` is able to handle dynamic content and adapt to screen size chang
1717
* [Installation](#installation)
1818
* [Usage](#usage)
1919
* [Props](#props)
20+
* [Usage with Safe Area Context](#safeArea)
2021
* [Troubleshooting](#troubleshooting)
2122
* [Upgrading](#upgrading)
2223
* [Contributing](#contributing)
@@ -292,27 +293,29 @@ class App extends React.Component {
292293

293294
## <a name="props"/>Props
294295

295-
Prop | Type | Optional | Default | Description
296-
----------------- | -------- | -------- | ----------- | -----------
297-
isVisible | bool | Yes | false | Show/Hide the popover
298-
mode | string | Yes | 'rn-modal' | One of: 'rn-modal', 'js-modal', 'tooltip'. See [Mode](#mode) section below for details.
299-
from | element OR ref OR rect | Yes | null | Either a React element, a function that returns a React element, a `ref` created from `React.createRef` or `React.useRef`, or a Rect object created by `new Rect(x, y, width, height)`.
300-
displayArea | rect | Yes | rect | Area where the popover is allowed to be displayed
301-
placement | string | Yes | 'auto' | How to position the popover - top &#124; bottom &#124; left &#124; right &#124; center &#124; auto. When 'auto' is specified, it will determine the ideal placement so that the popover is fully visible within `displayArea`.
302-
animationConfig | object | Yes | | An object containing any configuration options that can be passed to Animated.timing (e.g. `{ duration: 600, easing: Easing.inOut(Easing.quad) }`). The configuration options you pass will override the defaults for all animations.
303-
verticalOffset | number | Yes | 0 | The amount to vertically shift the popover on the screen. In certain Android configurations, you may need to apply a `verticalOffset` of `-StatusBar.currentHeight` for the popover to originate from the correct place.
304-
statusBarTranslucent | bool | Yes | null | For 'rn-modal' mode only. Determines whether the background should go under the status bar. Passed through to RN `Modal` component, see [their docs](https://reactnative.dev/docs/modal#statusbartranslucent-1) as well.
305-
safeAreaInsets | object | Yes | null | Inset configuration for the `SafeAreaView` wrapping the modal. This may be useful if you use popovers within views that render into the safe areas insets. Passed through to the `SafeAreaView` component, see [their docs](https://github.com/react-native-community/react-native-safe-area-view#forceinset) for usage.
306-
popoverStyle | object | Yes | {} | The style of the popover itself. You can override the `borderRadius`, `backgroundColor`, or any other [`style` prop for a `View`](https://facebook.github.io/react-native/docs/view-style-props.html).
307-
backgroundStyle | object | Yes | {} | The style of the background that fades in.
308-
arrowStyle | object | Yes | {} | The style of the arrow that points to the rect. Supported options are `width`, `height`, and `backgroundColor`. You can use `{backgroundColor: 'transparent'}` to hide the arrow completely.
309-
arrowShift | number | Yes | 0 | How much to shift the arrow to either side, as a multiplier. `-1` will shift it all the way to the left (or top) corner of the source view, while `1` will shift all the way to the right (or bottom) corner. A value of `0.5` or `-0.8` will shift it partly to one side.
310-
onOpenStart | function | Yes | | Callback to be fired when the open animation starts (before animation)
311-
onOpenComplete | function | Yes | | Callback to be fired when the open animation ends (after animation)
312-
onRequestClose | function | Yes | | Callback to be fired when the user taps outside the popover (on the background) or taps the "hardware" back button on Android
313-
onCloseStart | function | Yes | | Callback to be fired when the popover starts closing (before animation)
314-
onCloseComplete | function | Yes | | Callback to be fired when the popover is finished closing (after animation)
315-
debug | bool | Yes | false | Set this to `true` to turn on debug logging to the console. This is useful for figuring out why a Popover isn't showing.
296+
All props are optional
297+
298+
Prop | Type | Default | Description
299+
----------------- | -------- | ----------- | -----------
300+
isVisible | bool | false | Show/Hide the popover
301+
mode | string | 'rn-modal' | One of: 'rn-modal', 'js-modal', 'tooltip'. See [Mode](#mode) section below for details.
302+
from | element OR | Yes | null | Either a React element, a function that returns a React element, a `ref` created from `React.createRef` or `React.useRef`, or a Rect object created by `new Rect(x, y, width, height)`.
303+
displayArea | rect | rect | Area where the popover is allowed to be displayed
304+
placement | string | 'auto' | How to position the popover - top &#124; bottom &#124; left &#124; right &#124; center &#124; auto. When 'auto' is specified, it will determine the ideal placement so that the popover is fully visible within `displayArea`.
305+
animationConfig | object | | An object containing any configuration options that can be passed to Animated.timing (e.g. `{ duration: 600, easing: Easing.inOut(Easing.quad) }`). The configuration options you pass will override the defaults for all animations.
306+
verticalOffset | number | 0 | The amount to vertically shift the popover on the screen. In certain Android configurations, you may need to apply a `verticalOffset` of `-StatusBar.currentHeight` for the popover to originate from the correct place.
307+
statusBarTranslucent | bool | null | For 'rn-modal' mode only. Determines whether the background should go under the status bar. Passed through to RN `Modal` component, see [their docs](https://reactnative.dev/docs/modal#statusbartranslucent-1) as well.
308+
displayAreaInsets | object | { left: 10, right: 10, top: 20, bottom: 20 } | Insets to apply to the display area. The Popover will not be allowed to go beyond the display area minus the insets.
309+
popoverStyle | object | {} | The style of the popover itself. You can override the `borderRadius`, `backgroundColor`, or any other [`style` prop for a `View`](https://facebook.github.io/react-native/docs/view-style-props.html).
310+
backgroundStyle | object | {} | The style of the background that fades in.
311+
arrowStyle | object | {} | The style of the arrow that points to the rect. Supported options are `width`, `height`, and `backgroundColor`. You can use `{backgroundColor: 'transparent'}` to hide the arrow completely.
312+
arrowShift | number | 0 | How much to shift the arrow to either side, as a multiplier. `-1` will shift it all the way to the left (or top) corner of the source view, while `1` will shift all the way to the right (or bottom) corner. A value of `0.5` or `-0.8` will shift it partly to one side.
313+
onOpenStart | function | | Callback to be fired when the open animation starts (before animation)
314+
onOpenComplete | function | | Callback to be fired when the open animation ends (after animation)
315+
onRequestClose | function | | Callback to be fired when the user taps outside the popover (on the background) or taps the "hardware" back button on Android
316+
onCloseStart | function | | Callback to be fired when the popover starts closing (before animation)
317+
onCloseComplete | function | | Callback to be fired when the popover is finished closing (after animation)
318+
debug | bool | false | Set this to `true` to turn on debug logging to the console. This is useful for figuring out why a Popover isn't showing.
316319

317320
If no `from` is provided, the popover will float in the center of the screen.
318321

@@ -335,6 +338,22 @@ Shows the popover in the space provided, filling the `Popover` component's paren
335338

336339
Shows the `Popover` without taking over the screen, no background is faded in and taps to the area around the popover fall through to those views (as expected). The `onRequestClose` callback will never be called, so the `Popover` will have to be dismissed some other way.
337340

341+
## Usage with Safe Area Context
342+
343+
Some devices have notches or other screen features that create zones where you might want to avoid showing a `Popover`. To do so, follow the instructions to setup [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context), then use the provided hooks to pass the safe area insets straight to the `displayAreaInsets` prop:
344+
345+
```jsx
346+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
347+
import Popover from 'react-native-popover-view';
348+
349+
function PopoverSafeWrapper(props) {
350+
const insets = useSafeAreaInsets();
351+
return (
352+
<Popover {...props} displayAreaInsets={insets} />
353+
);
354+
}
355+
```
356+
338357
---
339358

340359
## <a name="troubleshooting" />Troubleshooting
@@ -365,6 +384,10 @@ import { Platform, StatusBar, ... } from 'react-native';
365384

366385
## <a name="upgrading" />Upgrading
367386

387+
#### `3.x` to `4.0`
388+
389+
Removed internal safe area view; if you want the Popover to avoid showing behind notches on some devices, follow the instructions: [Usage with Safe Area Context](#safeArea).
390+
368391
#### `2.x` to `3.0`
369392

370393
* `fromRect` and `fromView` have been consolidated into a single `from` prop, where you can pass a Rect or a Ref. All Refs passed in must now be a `RefObject` created from `React.createRef` or `React.useRef`. All Rects passed in must be an actual Rect object (e.g. `from={new Rect(x, y, width, height)}`).

package.json

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-popover-view",
3-
"version": "3.1.2",
3+
"version": "4.0.0",
44
"description": "A <Popover /> component for react-native iOS, Android, and Web",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
@@ -42,27 +42,25 @@
4242
},
4343
"devDependencies": {
4444
"@types/node": "^14.0.11",
45-
"@types/react": "^16.9.35",
46-
"@types/react-native": "^0.62.13",
45+
"@types/react": "^17.0.3",
46+
"@types/react-native": "^0.64.2",
4747
"@typescript-eslint/eslint-plugin": "^4.21.0",
4848
"@typescript-eslint/parser": "^4.21.0",
4949
"enzyme": "^3.10.0",
5050
"enzyme-adapter-react-16": "^1.14.0",
5151
"enzyme-to-json": "^3.3.5",
5252
"eslint": "^7.24.0",
5353
"eslint-plugin-react": "^7.23.2",
54-
"jest": "^24.8.0",
54+
"jest": "^26.6.3",
5555
"jest-serializer-enzyme": "^1.0.0",
5656
"patch-package": "^6.2.2",
5757
"postinstall-postinstall": "^2.1.0",
58-
"react": "^16.8.6",
58+
"react": "^17.0.2",
5959
"react-addons-test-utils": "^15.6.2",
60-
"react-dom": "^16.8.6",
61-
"react-native": "^0.62.2",
62-
"react-test-renderer": "^16.8.6",
63-
"typescript": "^3.9.3"
60+
"react-dom": "^17.0.2",
61+
"react-native": "^0.64.0",
62+
"react-test-renderer": "^17.0.2",
63+
"typescript": "^4.2.4"
6464
},
65-
"dependencies": {
66-
"react-native-safe-area-view": "0.14.9"
67-
}
65+
"dependencies": {}
6866
}

patches/@types+react-native+0.62.13.patch

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/Constants.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,4 @@
1-
import { Dimensions } from 'react-native';
2-
31
export const MULTIPLE_POPOVER_WARNING = `Popover Warning - Can't Show - Attempted to show a Popover while another one was already showing. You can only show one Popover at a time, and must wait for one to close completely before showing a different one. You can use the onCloseComplete prop to detect when a Popover has finished closing. To show multiple Popovers simultaneously, all but one should have mode={Popover.MODE.JS_MODAL}. Once you change the mode, you can show as many Popovers as you want, but you are responsible for keeping them above other views.`;
42

5-
// eslint-disable-next-line
6-
export enum Placement {
7-
TOP = 'top',
8-
RIGHT = 'right',
9-
BOTTOM = 'bottom',
10-
LEFT = 'left',
11-
AUTO = 'auto',
12-
CENTER = 'center'
13-
}
14-
15-
// eslint-disable-next-line
16-
export enum Mode {
17-
JS_MODAL = 'js-modal',
18-
RN_MODAL = 'rn-modal',
19-
TOOLTIP = 'tooltip'
20-
}
21-
223
export const DEFAULT_ARROW_SIZE = { width: 16, height: 8 };
234
export const DEFAULT_BORDER_RADIUS = 3;
24-
export const FIX_SHIFT = Dimensions.get('window').height * 2;
25-

src/Geometry.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { StyleProp, ViewStyle } from 'react-native';
2-
import { Placement } from './Constants';
2+
import { Placement } from './Types';
33
import { Rect, Size, Point, getArrowSize, getBorderRadius } from './Utility';
44

55
type ComputeGeometryBaseProps = {
@@ -464,7 +464,9 @@ function computeAutoGeometry(options: ComputeGeometryAutoProps): Geometry | null
464464
const arrowSize = getArrowSize(Placement.LEFT, arrowStyle);
465465

466466
// generating list of all possible sides with validity
467-
const spaceList: Record<Placement, PlacementOption> = {
467+
debug('computeAutoGeometry - displayArea', displayArea);
468+
debug('computeAutoGeometry - fromRect', fromRect);
469+
const spaceList: SpaceList = {
468470
[Placement.LEFT]: {
469471
sizeAvailable: fromRect.x - displayArea.x - arrowSize.width,
470472
sizeRequested: requestedContentSize.width
@@ -494,26 +496,33 @@ function computeAutoGeometry(options: ComputeGeometryAutoProps): Geometry | null
494496
switch (bestPlacementPosition) {
495497
case Placement.LEFT: return computeLeftGeometry(options);
496498
case Placement.RIGHT: return computeRightGeometry(options);
497-
case Placement.Bottom: return computeBottomGeometry(options);
499+
case Placement.BOTTOM: return computeBottomGeometry(options);
498500
case Placement.TOP: return computeTopGeometry(options);
499501
// Return nothing so popover will be placed in middle of screen
500502
default: return null;
501503
}
502504
}
503505

506+
type SpaceList = Record<
507+
Placement.LEFT | Placement.RIGHT | Placement.TOP | Placement.BOTTOM,
508+
PlacementOption
509+
>
504510
type PlacementOption = {
505-
sizeRequested: boolean;
511+
sizeRequested: number;
506512
sizeAvailable: number;
507513
}
508-
function findBestPlacement(spaceList: Record<Placement, PlacementOption>): Placement | null {
509-
return Object.entries(spaceList).reduce(
510-
(bestPlacement, [placement, { sizeRequested, sizeAvailable }]) => (
514+
function findBestPlacement(spaceList: SpaceList): Placement | null {
515+
return Object.keys(spaceList).reduce(
516+
(bestPlacement, placement) => (
511517
// If it can fit, and is the first one or fits better than the last one, use this placement
512-
sizeRequested <= sizeAvailable &&
513-
(!bestPlacement || sizeAvailable > spaceList[bestPlacement].sizeAvailable)
514-
? placement
518+
spaceList[placement].sizeRequested <= spaceList[placement].sizeAvailable &&
519+
(
520+
!bestPlacement ||
521+
spaceList[placement].sizeAvailable > spaceList[bestPlacement].sizeAvailable
522+
)
523+
? placement as Placement
515524
: bestPlacement
516525
),
517-
null
526+
null as Placement | null
518527
);
519528
}

0 commit comments

Comments
 (0)