context menu and popover to support rtl layout

This commit is contained in:
Martin Bielik 2017-12-20 16:06:24 +01:00
parent d3472de504
commit 25a8916778
3 changed files with 36 additions and 26 deletions

View File

@ -10,6 +10,7 @@
android:minSdkVersion="16"
android:targetSdkVersion="22" />
<!-- To enable RTL use android:supportsRtl="true" -->
<application
android:name=".MainApplication"
android:allowBackup="true"

View File

@ -1,5 +1,5 @@
import React from 'react';
import { Animated, Easing, StyleSheet } from 'react-native';
import { I18nManager, Animated, Easing, StyleSheet } from 'react-native';
import { OPEN_ANIM_DURATION, CLOSE_ANIM_DURATION } from '../constants';
const axisPosition = (oDim, wDim, tPos, tDim) => {
@ -29,13 +29,14 @@ const axisPosition = (oDim, wDim, tPos, tDim) => {
return pos;
};
export const computePosition = ({ windowLayout, triggerLayout, optionsLayout }) => {
export const computePosition = ({ windowLayout, triggerLayout, optionsLayout }, isRTL) => {
const { x: wX, y: wY, width: wWidth, height: wHeight } = windowLayout;
const { x: tX, y: tY, height: tHeight, width: tWidth } = triggerLayout;
const { height: oHeight, width: oWidth } = optionsLayout;
const top = axisPosition(oHeight, wHeight, tY - wY, tHeight);
const left = axisPosition(oWidth, wWidth, tX - wX, tWidth);
return { top, left };
const start = isRTL ? 'right' : 'left';
return { top, [start]: left };
};
export default class ContextMenu extends React.Component {
@ -73,7 +74,7 @@ export default class ContextMenu extends React.Component {
transform: [ { scale: this.state.scaleAnim } ],
opacity: this.state.scaleAnim,
};
const position = computePosition(layouts);
const position = computePosition(layouts, I18nManager.isRTL);
return (
<Animated.View {...other} style={[styles.options, style, animation, position]}>
{children}

View File

@ -1,4 +1,4 @@
import { Animated, Easing, StyleSheet, View } from 'react-native';
import { I18nManager, Animated, Easing, StyleSheet, View } from 'react-native';
import React from 'react';
import PropTypes from 'prop-types';
@ -88,52 +88,56 @@ function getRightPrice(hOptions, vOptions) {
return centerOffset + sideOffset
}
function topProperties(hOptions, vOptions) {
function getStartPosKey(isRTL) {
return isRTL ? 'right' : 'left';
}
function topProperties(hOptions, vOptions, isRTL) {
const centered = axisCenteredPositionProperties(vOptions);
const side = axisNegativeSideProperties(hOptions);
return {
position: {
top: side.position,
left: centered.position,
[getStartPosKey(isRTL)]: centered.position,
},
offset: centered.offset,
placement: 'top',
};
}
function bottomProperties(hOptions, vOptions) {
function bottomProperties(hOptions, vOptions, isRTL) {
const centered = axisCenteredPositionProperties(vOptions);
const side = axisPositiveSideProperties(hOptions);
return {
position: {
top: side.position,
left: centered.position,
[getStartPosKey(isRTL)]: centered.position,
},
offset: centered.offset,
placement: 'bottom',
};
}
function rightProperties(hOptions, vOptions) {
function rightProperties(hOptions, vOptions, isRTL) {
const centered = axisCenteredPositionProperties(hOptions);
const side = axisPositiveSideProperties(vOptions);
return {
position: {
top: centered.position,
left: side.position,
[getStartPosKey(isRTL)]: side.position,
},
offset: centered.offset,
placement: 'right',
};
}
function leftProperties(hOptions, vOptions) {
function leftProperties(hOptions, vOptions, isRTL) {
const centered = axisCenteredPositionProperties(hOptions);
const side = axisNegativeSideProperties(vOptions);
return {
position: {
top: centered.position,
left: side.position,
[getStartPosKey(isRTL)]: side.position,
},
offset: centered.offset,
placement: 'left',
@ -158,7 +162,8 @@ const propertiesByPlacement = {
export function computeProperties (
{ windowLayout, triggerLayout, optionsLayout },
placement,
preferredPlacement
preferredPlacement,
isRTL,
) {
const { x: wX, y: wY, width: wWidth, height: wHeight } = windowLayout;
const { x: tX, y: tY, height: tHeight, width: tWidth } = triggerLayout;
@ -176,7 +181,7 @@ export function computeProperties (
tDim: tWidth,
};
if (placement !== 'auto' && propertiesByPlacement[placement]) {
return propertiesByPlacement[placement](hOptions, vOptions)
return propertiesByPlacement[placement](hOptions, vOptions, isRTL)
}
const prices = {
@ -190,7 +195,7 @@ export function computeProperties (
? preferredPlacement
: Object.keys(prices).find(pl => prices[pl] === bestPrice)
return propertiesByPlacement[bestPlacement](hOptions, vOptions)
return propertiesByPlacement[bestPlacement](hOptions, vOptions, isRTL)
}
export default class Popover extends React.Component {
@ -232,6 +237,7 @@ export default class Popover extends React.Component {
placement: userPlacement,
...other,
} = this.props;
const isRTL = I18nManager.isRTL;
const animation = {
transform: [ { scale: this.state.scaleAnim } ],
opacity: this.state.scaleAnim,
@ -239,7 +245,8 @@ export default class Popover extends React.Component {
const { position, placement, offset } = computeProperties(
layouts,
userPlacement,
preferredPlacement
preferredPlacement,
isRTL,
);
return (
<Animated.View
@ -247,14 +254,14 @@ export default class Popover extends React.Component {
styles.animated,
animation,
position,
containerStyle[placement],
getContainerStyle({ placement, isRTL }),
]}
pointerEvents="box-none"
>
<View
style={[
styles.anchor,
dynamicAnchorStyle({ placement, offset }),
dynamicAnchorStyle({ placement, offset, isRTL }),
anchorStyle,
]}
/>
@ -282,12 +289,12 @@ Popover.defaultProps = {
placement: 'auto',
};
const containerStyle = {
const getContainerStyle = ({ placement, isRTL }) => ({
left: {
flexDirection: 'row-reverse',
flexDirection: isRTL ? 'row' : 'row-reverse',
},
right: {
flexDirection: 'row',
flexDirection: isRTL ? 'row-reverse' : 'row',
},
top: {
flexDirection: 'column-reverse',
@ -295,9 +302,10 @@ const containerStyle = {
bottom: {
flexDirection: 'column',
},
}
})[placement]
const dynamicAnchorStyle = ({ offset, placement }) => {
const dynamicAnchorStyle = ({ offset, placement, isRTL }) => {
const start = getStartPosKey(isRTL);
switch (placement) {
case 'right':
return {
@ -317,7 +325,7 @@ const dynamicAnchorStyle = ({ offset, placement }) => {
};
case 'top':
return {
left: offset,
[start]: offset,
transform: [
{ translateY: -anchorOffset },
{ rotate: '45deg' },
@ -325,7 +333,7 @@ const dynamicAnchorStyle = ({ offset, placement }) => {
};
case 'bottom':
return {
left: offset,
[start]: offset,
transform: [
{ translateY: anchorOffset },
{ rotate: '45deg' },