Skip to content

side bar is not sticking in rtl on fixed position while working fine in English. #49002

Description

@sheharyarusol

Description

import React, { useState, useRef, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Animated, Dimensions, Text, View, StyleSheet } from 'react-native';
import get from 'lodash.get';
import {I18nManager} from 'react-native'
// import { getFormattedCurrency } from '~/utils/units'

const ComparisonTableRow = (props) => {
const {
data = [],
comparing,
getBestBy,
fixed,
cellTextAlign,
headerCellContent,
headerCellStyle,
cellContent,
cellStyle,
rowStyle,
bestCellStyle,
bestCellTextStyle,
mergeCells,

isHighlightBest,
headerCellWidth,
cellWidth,
innerScrollX,
scrollY

} = props;

let bestValueIndices = [];
// Only sort them if user provide getBestBy order string/comparison function to sort the values
if (comparing && getBestBy) {
const valuesOriginal =
typeof comparing === 'function'
? comparing(data)
: data.map((item) => getComparingValue(item, comparing));

const valuesSorted = getSortedValues(valuesOriginal, getBestBy);

// if bestValueIndices is -1, either there is no best or getBestBy is null
bestValueIndices = getBestValueIndices(valuesOriginal, valuesSorted);

}

const isAllValuesEqual = bestValueIndices.length === data.length;

const mergedBestCellStyle = {
...styles.bestCell,
...bestCellStyle
};

const mergedBestCellTextStyle = {
...styles.bestCellText,
...bestCellTextStyle
};

function getComparingValue(item, comparing) {
return get(item, comparing);
}

function getSortedValues(valuesOriginal, getBestBy) {
let valuesSorted = [...valuesOriginal];
if (typeof getBestBy === 'function') {
valuesSorted.sort(getBestBy);
} else if (getBestBy === 'asc') {
valuesSorted.sort((a, b) => a - b);
} else if (getBestBy === 'desc') {
valuesSorted.sort((a, b) => b - a);
}
return valuesSorted;
}

function getBestValueIndices(valuesOriginal, valuesSorted) {
const [bestValue] = valuesSorted;
let bestValueIndices = [];
if (bestValue !== undefined) {
valuesOriginal.forEach((value, i) => {
if (value === bestValue) {
bestValueIndices.push(i);
}
});
} else {
bestValueIndices = [-1];
}
return bestValueIndices;
}

function renderHeaderCellContent() {

return (
  <Animated.View
    style={[
      styles.headerCell,
      { width: headerCellWidth },
      headerCellStyle,
      innerScrollX && {
        transform: [
          {
            translateX: innerScrollX.interpolate({
              inputRange: [0, I18nManager.isRTL ? 10: 3000],
              outputRange: [0, I18nManager.isRTL ? 10: 3000],
              extrapolate: 'clamp'
            })
          }
        ]
      }
    ]}
  >
    {/* {typeof headerCellContent === 'function' ? (
      headerCellContent()
    ) : ( */}
      <Text style={styles.headerCellText}>{headerCellContent}</Text>
    {/* )} */}
  </Animated.View>
);

}

function renderTemplateCellContent(cellContent, item) {
const comparingValue = getComparingValue(item, comparing);
if (comparing && !comparingValue) {
return '-';
}

return comparingValue;

}

function renderCustomCellContent(
cellContent,
index,
item,
isBest,
mergedBestCellTextStyle
) {
let customCellContent = cellContent({
item,
index,
isBest,
cellTextStyle: styles.cellText,
bestCellTextStyle: mergedBestCellTextStyle
});

if (React.isValidElement(customCellContent)) {
  return customCellContent;
}

return (
  <Text
    style={[
      styles.cellText,
      cellTextAlign && { textAlign: cellTextAlign },
      isBest && mergedBestCellTextStyle
    ]}
  >
    {renderTemplateCellContent(customCellContent, item)}
  </Text>
);

}

return (
<Animated.View
style={[
styles.row,
rowStyle,
fixed &&
scrollY && {
...styles.fixedRow,
transform: [
{
translateY: scrollY.interpolate({
inputRange: [0, 10000],
outputRange: [0, 10000],
extrapolate: 'clamp'
})
}
]
}
]}
>
{headerCellContent !== undefined && renderHeaderCellContent()}
{mergeCells ? (
<Animated.View
style={[
styles.mergedCell,
{ width: Dimensions.get('window').width - headerCellWidth },
cellStyle,
innerScrollX && {
transform: [
{
translateX: innerScrollX.interpolate({
inputRange: [0, 1000],
outputRange: [0, 1000],
extrapolate: 'clamp'
})
}
]
}
]}
>
{cellContent && typeof cellContent === 'function'
? cellContent({ data })
: null}
</Animated.View>
) : (
data.map((item, index) => {
const isBest =
bestValueIndices.includes(index) &&
isHighlightBest &&
!isAllValuesEqual;
return (
<View
style={[
styles.cell,
cellStyle,
{ width: cellWidth },
isBest && mergedBestCellStyle
]}
key={index}
>
{typeof cellContent === 'function' ? (
renderCustomCellContent(
cellContent,
index,
item,
isBest,
mergedBestCellTextStyle
)
) : (
<Text
style={[
styles.cellText,
cellTextAlign && { textAlign: cellTextAlign },
isBest && mergedBestCellTextStyle
]}
>
{renderTemplateCellContent(cellContent, item)}

)}

);
})
)}
</Animated.View>
);
};

const styles = StyleSheet.create({
row: {
borderTopWidth: 1,
borderColor: '#E5E5E5',
flexDirection: 'row'
},
fixedRow: {
position: 'relative',
zIndex: 100
},
headerCell: {
position: 'relative',
zIndex: 10,
backgroundColor: '#F9F9FB',
paddingVertical: 11,
paddingHorizontal: 12,
borderRightWidth: 1,
borderColor: '#E5E5E5'
},
cell: {
backgroundColor: '#FFF',
paddingVertical: 10,
paddingHorizontal: 14,
borderRightWidth: 1,
borderColor: '#E5E5E5'
},
mergedCell: {
justifyContent: 'center',
paddingVertical: 10,
paddingHorizontal: 12
},
headerCellText: {
fontSize: 20
},
cellText: {
fontSize: 20
},
bestCell: {
backgroundColor: 'rgba(255,236,170,0.2)'
},
bestCellText: {
color: '#F6571A',
fontWeight: 'bold'
}
});

ComparisonTableRow.propTypes = {
data: PropTypes.array,
comparing: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
getBestBy: PropTypes.oneOfType([
PropTypes.oneOf(['asc', 'desc']),
PropTypes.func
]),
headerCellContent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
headerCellStyle: PropTypes.object,
cellContent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
cellStyle: PropTypes.object,
rowStyle: PropTypes.object,
bestCellStyle: PropTypes.object,
bestCellTextStyle: PropTypes.object,
isHighlightBest: PropTypes.bool,
innerScrollX: PropTypes.object
};

ComparisonTableRow.defaultProps = {};

export default ComparisonTableRow;

code responsible for this:
<Animated.View
style={[
styles.headerCell,
{ width: headerCellWidth },
headerCellStyle,
innerScrollX && {
transform: [
{
translateX: innerScrollX.interpolate({
inputRange: [0, I18nManager.isRTL ? 10: 3000],
outputRange: [0, I18nManager.isRTL ? 10: 3000],
extrapolate: 'clamp'
})
}
]
}
]}
>

      <Text style={styles.headerCellText}>{headerCellContent}</Text>
  </Animated.View>

Steps to reproduce

unable to reproduce

React Native Version

0.76.5

Affected Platforms

Runtime - Android, Runtime - iOS

Output of npx react-native info

System:
  OS: macOS 14.6.1
  CPU: (8) x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
  Memory: 56.37 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.12.0
    path: ~/.nvm/versions/node/v22.12.0/bin/node
  Yarn:
    version: 1.22.22
    path: /usr/local/bin/yarn
  npm:
    version: 10.9.0
    path: ~/.nvm/versions/node/v22.12.0/bin/npm
  Watchman:
    version: 2024.12.02.00
    path: /usr/local/bin/watchman
Managers:
  CocoaPods:
    version: 1.16.2
    path: /usr/local/lib/ruby/gems/3.3.0/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.2
      - iOS 18.2
      - macOS 15.2
      - tvOS 18.2
      - visionOS 2.2
      - watchOS 11.2
  Android SDK: Not Found
IDEs:
  Android Studio: 2024.2 AI-242.23339.11.2421.12700392
  Xcode:
    version: 16.2/16C5032a
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.13
    path: /usr/bin/javac
  Ruby:
    version: 3.3.6
    path: /usr/local/opt/ruby/bin/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 15.0.1
    wanted: 15.0.1
  react:
    installed: 18.3.1
    wanted: 18.3.1
  react-native:
    installed: 0.76.5
    wanted: 0.76.5
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false

Stacktrace or Logs

no lots

Reproducer

no reproducer

Screenshots and Videos

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: AttentionIssues where the author has responded to feedback.Needs: ReproThis issue could be improved with a clear list of steps to reproduce the issue.Newer Patch Available

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions