UNPKG

react-native-safe-area-view

Version:

Add padding to your views to account for notches, home indicators, status bar, and possibly other future things.

1 lines 16 kB
{"version":3,"sources":["index.tsx"],"names":["React","Animated","Dimensions","InteractionManager","StyleSheet","SafeAreaContext","SafeAreaProvider","SafeAreaConsumer","useSafeArea","shallowEquals","SafeAreaView","_isMounted","_view","createRef","state","touchesTop","touchesBottom","touchesLeft","touchesRight","viewWidth","viewHeight","_handleLayout","e","props","onLayout","_updateMeasurements","current","getResolvedDimensions","WIDTH","width","HEIGHT","height","view","measureInWindow","getNode","realX","realY","winWidth","winHeight","nextState","setState","_getSafeAreaStyle","forceInset","_getViewStyles","paddingTop","paddingBottom","paddingLeft","paddingRight","viewStyle","style","_getInset","getKeys","forEach","key","inset","Math","max","flatten","padding","paddingVertical","paddingHorizontal","doubleFromPercentString","context","Error","left","right","top","bottom","runAfterInteractions","Component","contextType","get","percent","includes","dbl","parseFloat","isNaN","object","Object","keys"],"mappings":"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","sourcesContent":["import * as React from 'react';\nimport {\n Animated,\n Dimensions,\n InteractionManager,\n LayoutChangeEvent,\n StyleSheet,\n View,\n ViewStyle,\n ViewProperties,\n} from 'react-native';\nimport {\n EdgeInsets,\n SafeAreaContext,\n SafeAreaProvider,\n SafeAreaConsumer,\n useSafeArea,\n} from 'react-native-safe-area-context';\n\nimport shallowEquals from './shallowEquals';\n\n// Re-export react-native-safe-area-context utilities\nexport { useSafeArea, SafeAreaProvider, SafeAreaConsumer, SafeAreaContext };\n\nexport type ForceInsetValue = 'always' | 'never';\nexport type ForceInsetProp = {\n top?: ForceInsetValue;\n bottom?: ForceInsetValue;\n left?: ForceInsetValue;\n right?: ForceInsetValue;\n horizontal?: ForceInsetValue;\n vertical?: ForceInsetValue;\n};\n\ninterface Props extends ViewProperties {\n forceInset?: ForceInsetProp;\n}\n\ninterface State {\n touchesTop: boolean;\n touchesBottom: boolean;\n touchesLeft: boolean;\n touchesRight: boolean;\n viewWidth: number;\n viewHeight: number;\n}\n\n// https://github.com/facebook/react-native/blob/282b8b04e167cb426e40947064c4c18186e093f5/Libraries/ReactNative/DummyUIManager.js#L64\ninterface AnimatedView extends Animated.AnimatedComponent<View> {\n measureInWindow: (\n callback: (x: number, y: number, width: number, height: number) => void\n ) => void;\n}\n\nexport default class SafeAreaView extends React.Component<Props, State> {\n static contextType: any = SafeAreaContext;\n context!: React.ContextType<typeof SafeAreaContext>;\n private _isMounted: boolean = false;\n private _view = React.createRef<AnimatedView>();\n\n state: State = {\n touchesTop: true,\n touchesBottom: true,\n touchesLeft: true,\n touchesRight: true,\n viewWidth: 0,\n viewHeight: 0,\n };\n\n componentDidMount() {\n this._isMounted = true;\n InteractionManager.runAfterInteractions(() => {\n this._updateMeasurements();\n });\n }\n\n componentWillUnmount() {\n this._isMounted = false;\n }\n\n render() {\n const { forceInset = false, style, ...props } = this.props;\n\n return (\n <Animated.View\n // @ts-ignore\n ref={this._view}\n pointerEvents=\"box-none\"\n {...props}\n onLayout={this._handleLayout}\n style={this._getSafeAreaStyle()}\n />\n );\n }\n\n _handleLayout = (e: LayoutChangeEvent) => {\n if (this.props.onLayout) this.props.onLayout(e);\n\n this._updateMeasurements();\n };\n\n _updateMeasurements = () => {\n if (!this._isMounted) return;\n if (!this._view.current) return;\n\n const { width: WIDTH, height: HEIGHT } = getResolvedDimensions();\n\n // calling getNode on the ref is no longer necessary in the future\n const view = this._view.current.measureInWindow\n ? this._view.current\n : this._view.current.getNode();\n view.measureInWindow((realX, realY, winWidth, winHeight) => {\n if (!this._view.current) {\n return;\n }\n\n if (realY >= HEIGHT) {\n realY = realY % HEIGHT;\n } else if (realY < 0) {\n realY = (realY % HEIGHT) + HEIGHT;\n }\n\n if (realX >= WIDTH) {\n realX = realX % WIDTH;\n } else if (realX < 0) {\n realX = (realX % WIDTH) + WIDTH;\n }\n\n let nextState = {\n touchesTop: realY === 0,\n touchesBottom: realY + winHeight >= HEIGHT,\n touchesLeft: realX === 0,\n touchesRight: realX + winWidth >= WIDTH,\n viewWidth: winWidth,\n viewHeight: winHeight,\n };\n\n if (!shallowEquals(nextState, this.state)) {\n this.setState(nextState);\n }\n });\n };\n\n _getSafeAreaStyle = () => {\n const { touchesTop, touchesBottom, touchesLeft, touchesRight } = this.state;\n const { forceInset } = this.props;\n\n const {\n paddingTop,\n paddingBottom,\n paddingLeft,\n paddingRight,\n viewStyle,\n } = this._getViewStyles();\n\n const style = {\n ...viewStyle,\n paddingTop: touchesTop ? this._getInset('top') : 0,\n paddingBottom: touchesBottom ? this._getInset('bottom') : 0,\n paddingLeft: touchesLeft ? this._getInset('left') : 0,\n paddingRight: touchesRight ? this._getInset('right') : 0,\n };\n\n if (forceInset && typeof forceInset !== 'boolean') {\n getKeys(forceInset).forEach(key => {\n let inset = 0;\n\n if (forceInset[key] === 'always') {\n inset = this._getInset(key);\n } else if (forceInset[key] === 'never') {\n inset = 0;\n }\n\n switch (key) {\n case 'horizontal': {\n style.paddingLeft = inset;\n style.paddingRight = inset;\n break;\n }\n case 'vertical': {\n style.paddingTop = inset;\n style.paddingBottom = inset;\n break;\n }\n case 'left': {\n style.paddingLeft = inset;\n break;\n }\n case 'right': {\n style.paddingRight = inset;\n break;\n }\n case 'top': {\n style.paddingTop = inset;\n break;\n }\n case 'bottom': {\n style.paddingBottom = inset;\n break;\n }\n }\n });\n }\n\n // new height/width should only include padding from insets\n // height/width should not be affected by padding from style obj\n if (style.height && typeof style.height === 'number') {\n style.height += style.paddingTop + style.paddingBottom;\n }\n\n if (style.width && typeof style.width === 'number') {\n style.width += style.paddingLeft + style.paddingRight;\n }\n\n style.paddingTop = Math.max(style.paddingTop, paddingTop);\n style.paddingBottom = Math.max(style.paddingBottom, paddingBottom);\n style.paddingLeft = Math.max(style.paddingLeft, paddingLeft);\n style.paddingRight = Math.max(style.paddingRight, paddingRight);\n\n return style;\n };\n\n _getViewStyles = () => {\n const { viewWidth } = this.state;\n // get padding values from style to add back in after insets are determined\n // default precedence: padding[Side] -> vertical | horizontal -> padding -> 0\n let {\n padding = 0,\n paddingVertical = padding,\n paddingHorizontal = padding,\n paddingTop = paddingVertical,\n paddingBottom = paddingVertical,\n paddingLeft = paddingHorizontal,\n paddingRight = paddingHorizontal,\n ...viewStyle\n }: ViewStyle = StyleSheet.flatten(this.props.style || {});\n\n if (typeof paddingTop !== 'number') {\n paddingTop = doubleFromPercentString(paddingTop) * viewWidth;\n }\n\n if (typeof paddingBottom !== 'number') {\n paddingBottom = doubleFromPercentString(paddingBottom) * viewWidth;\n }\n\n if (typeof paddingLeft !== 'number') {\n paddingLeft = doubleFromPercentString(paddingLeft) * viewWidth;\n }\n\n if (typeof paddingRight !== 'number') {\n paddingRight = doubleFromPercentString(paddingRight) * viewWidth;\n }\n\n return {\n paddingTop,\n paddingBottom,\n paddingLeft,\n paddingRight,\n viewStyle,\n };\n };\n\n _getInset = (key: keyof ForceInsetProp) => {\n if (this.context === null) {\n throw new Error(\n '<SafeAreaView /> must be wrapped by react-native-safe-area-context <SafeAreaProvider />'\n );\n } else if (key === 'horizontal') {\n return Math.max(this.context.left, this.context.right);\n } else if (key === 'vertical') {\n return Math.max(this.context.top, this.context.bottom);\n } else {\n return this.context[key as keyof EdgeInsets];\n }\n };\n}\n\n// note(brentvatne): it is unclear to me why this function exists but I will\n// leave it\nfunction getResolvedDimensions() {\n const { width, height } = Dimensions.get('window');\n if (width === 0 && height === 0) return Dimensions.get('screen');\n return { width, height };\n}\n\n// Convert percentage string, eg: 50%, to double, eg: 0.5\nfunction doubleFromPercentString(percent: string): number {\n if (!percent.includes('%')) {\n return 0;\n }\n\n const dbl = parseFloat(percent) / 100;\n\n if (isNaN(dbl)) return 0;\n\n return dbl;\n}\n\n// Utility to iterate over keys in object and have each key typed\nfunction getKeys<T extends {}>(object: T): Array<keyof T> {\n return Object.keys(object) as Array<keyof T>;\n}\n"]}