Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: RocketChat/Rocket.Chat.ReactNative
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: f65bf9a46f9a28e01e0d011c9dc331dcd4ff9a83
Choose a base ref
..
head repository: RocketChat/Rocket.Chat.ReactNative
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4f7d5bbcfc47d54eb10975dc19fab5fdd73bcb76
Choose a head ref
20 changes: 20 additions & 0 deletions app/containers/A11yFlow/A11yContainer/A11yContainer.ios.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { useRef } from 'react';
import { View, ViewProps } from 'react-native';

import { AccessibilityOrderProvider } from '../contexts/useAccessibilityOrder';

interface IA11yContainer extends ViewProps {}

const A11yContainer = ({ children, ...rest }: IA11yContainer) => {
const containerRef = useRef<View>(null);

return (
<AccessibilityOrderProvider containerRef={containerRef}>
<View {...rest} ref={containerRef}>
{children}
</View>
</AccessibilityOrderProvider>
);
};

export default A11yContainer;
7 changes: 7 additions & 0 deletions app/containers/A11yFlow/A11yContainer/A11yContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ViewProps } from 'react-native';

interface IA11yContainer extends ViewProps {}

const A11yContainer = ({ children }: IA11yContainer) => children;

export default A11yContainer;
32 changes: 32 additions & 0 deletions app/containers/A11yFlow/A11yElement/A11yElement.ios.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useEffect, useRef } from 'react';
import { View, ViewProps, findNodeHandle } from 'react-native';

import { useAccessibilityOrder } from '../contexts/useAccessibilityOrder';

interface IA11yElementProps extends ViewProps {
order?: number;
}

const A11yElement = ({ order, children, ...rest }: IA11yElementProps) => {
const elementRef = useRef<View>(null);
const { updateElementsList } = useAccessibilityOrder();

const handleUpdateOrder = () => {
const tag = findNodeHandle(elementRef.current);
if (!tag) return;

updateElementsList({ tag, order });
};

useEffect(() => {
handleUpdateOrder();
}, []);

return (
<View {...rest} ref={elementRef}>
{children}
</View>
);
};

export default A11yElement;
9 changes: 9 additions & 0 deletions app/containers/A11yFlow/A11yElement/A11yElement.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { View, ViewProps } from 'react-native';

interface IA11yElementProps extends ViewProps {
order?: number;
}

const A11yElement = ({ children, ...rest }: IA11yElementProps) => <View {...rest}>{children}</View>;

export default A11yElement;
14 changes: 14 additions & 0 deletions app/containers/A11yFlow/A11yFlowModule/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { NativeModules, Platform } from 'react-native';

const { A11yFlow } = NativeModules;

const A11yFlowModule = Platform.select({
ios: {
setA11yOrder: (elements: number[], node: number) => {
if (!node || !elements) return;
A11yFlow.setA11yOrder(elements, node);
}
}
});

export default A11yFlowModule;
53 changes: 53 additions & 0 deletions app/containers/A11yFlow/contexts/useAccessibilityOrder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import { findNodeHandle, View } from 'react-native';

import A11yFlowModule from '../A11yFlowModule';

interface IElement {
tag: number;
order?: number;
}
interface IAccessibilityContextData {
updateElementsList: (element: IElement) => void;
}

interface IAccessibilityOrderProviderProps {
children: React.ReactNode;
containerRef: React.RefObject<View>;
}

export const AccessibilityOrderContext = createContext({} as IAccessibilityContextData);

function AccessibilityOrderProvider({ children, containerRef }: IAccessibilityOrderProviderProps) {
const [elements, setElements] = useState<IElement[]>([]);

const sortElements = (elementsList: IElement[]) => elementsList.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));

const extractTags = (elements: IElement[]) => elements.map(item => item.tag);

const updateElementsList = (element: IElement) => {
setElements(prevState => sortElements([...prevState, element]));
};

const updateAccessibilityOrder = () => {
const parentTag = findNodeHandle(containerRef.current);

if (!parentTag) return;

A11yFlowModule?.setA11yOrder(extractTags(elements), parentTag);
};

useEffect(() => {
updateAccessibilityOrder();
}, [elements]);

return <AccessibilityOrderContext.Provider value={{ updateElementsList }}>{children}</AccessibilityOrderContext.Provider>;
}

function useAccessibilityOrder() {
const context = useContext(AccessibilityOrderContext);

return context;
}

export { AccessibilityOrderProvider, useAccessibilityOrder };
4 changes: 4 additions & 0 deletions app/containers/A11yFlow/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import A11yElement from './A11yElement/A11yElement';
import A11yContainer from './A11yContainer/A11yContainer';

export { A11yContainer, A11yElement };
2 changes: 1 addition & 1 deletion app/containers/EmojiPicker/EmojiCategory.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { FlatList } from 'react-native-gesture-handler';
import { FlatList } from 'react-native';

import { IEmoji } from '../../definitions/IEmoji';
import scrollPersistTaps from '../../lib/methods/helpers/scrollPersistTaps';
186 changes: 97 additions & 89 deletions app/containers/TextInput/FormTextInput.tsx
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import ActivityIndicator from '../ActivityIndicator';
import { CustomIcon, TIconsName } from '../CustomIcon';
import { TextInput } from './TextInput';
import { isIOS } from '../../lib/methods/helpers';
import { A11yContainer, A11yElement } from '../A11yFlow';

const styles = StyleSheet.create({
error: {
@@ -100,101 +101,108 @@ export const FormTextInput = ({
const Input = bottomSheet ? BottomSheetTextInput : TextInput;

const accessibilityLabelRequired = required ? `, ${i18n.t('Required')}` : '';
const accessibilityInputValue = (!secureTextEntry && value && isIOS) || showPassword ? `, ${value}` : '';
const accessibilityInputValue = (!secureTextEntry && value && isIOS) || showPassword ? `, ${value ?? ''}` : '';
return (
<View
accessible
accessibilityLabel={`${label}${accessibilityLabelRequired}${accessibilityInputValue}`}
style={[styles.inputContainer, containerStyle]}>
{label ? (
<Text style={[styles.label, { color: colors.fontTitlesLabels }, error?.error && { color: colors.fontDanger }]}>
{label}{' '}
{required && <Text style={[styles.required, { color: colors.fontSecondaryInfo }]}>{`(${i18n.t('Required')})`}</Text>}
</Text>
) : null}
<A11yContainer>
<A11yElement order={1}>
<View
accessible
accessibilityLabel={`${label}${accessibilityLabelRequired}${accessibilityInputValue}`}
style={[styles.inputContainer, containerStyle]}>
{label ? (
<Text style={[styles.label, { color: colors.fontTitlesLabels }, error?.error && { color: colors.fontDanger }]}>
{label}{' '}
{required && (
<Text style={[styles.required, { color: colors.fontSecondaryInfo }]}>{`(${i18n.t('Required')})`}</Text>
)}
</Text>
) : null}

<View accessible style={styles.wrap}>
<Input
style={[
styles.input,
iconLeft && styles.inputIconLeft,
(secureTextEntry || iconRight || showClearInput) && styles.inputIconRight,
{
backgroundColor: colors.surfaceRoom,
borderColor: colors.strokeMedium,
color: colors.fontTitlesLabels
},
error?.error && {
color: colors.buttonBackgroundDangerDefault,
borderColor: colors.buttonBackgroundDangerDefault
},
inputStyle
]}
// @ts-ignore ref error
ref={inputRef}
autoCorrect={false}
autoCapitalize='none'
underlineColorAndroid='transparent'
secureTextEntry={secureTextEntry && !showPassword}
testID={testID}
placeholder={placeholder}
value={value}
placeholderTextColor={colors.fontAnnotation}
{...inputProps}
/>
<View accessible style={styles.wrap}>
<Input
style={[
styles.input,
iconLeft && styles.inputIconLeft,
(secureTextEntry || iconRight || showClearInput) && styles.inputIconRight,
{
backgroundColor: colors.surfaceRoom,
borderColor: colors.strokeMedium,
color: colors.fontTitlesLabels
},
error?.error && {
color: colors.buttonBackgroundDangerDefault,
borderColor: colors.buttonBackgroundDangerDefault
},
inputStyle
]}
// @ts-ignore ref error
ref={inputRef}
autoCorrect={false}
autoCapitalize='none'
underlineColorAndroid='transparent'
secureTextEntry={secureTextEntry && !showPassword}
testID={testID}
placeholder={placeholder}
value={value}
placeholderTextColor={colors.fontAnnotation}
{...inputProps}
/>

{iconLeft ? (
<CustomIcon
name={iconLeft}
testID={testID ? `${testID}-icon-left` : undefined}
size={20}
color={colors.fontSecondaryInfo}
style={[styles.iconContainer, styles.iconLeft]}
/>
) : null}
{iconLeft ? (
<CustomIcon
name={iconLeft}
testID={testID ? `${testID}-icon-left` : undefined}
size={20}
color={colors.fontSecondaryInfo}
style={[styles.iconContainer, styles.iconLeft]}
/>
) : null}

{showClearInput ? (
<Touchable onPress={onClearInput} style={[styles.iconContainer, styles.iconRight]} testID='clear-text-input'>
<CustomIcon name='input-clear' size={20} color={colors.fontDefault} />
</Touchable>
) : null}
{showClearInput ? (
<Touchable onPress={onClearInput} style={[styles.iconContainer, styles.iconRight]} testID='clear-text-input'>
<CustomIcon name='input-clear' size={20} color={colors.fontDefault} />
</Touchable>
) : null}

{iconRight && !showClearInput ? (
<CustomIcon
name={iconRight}
testID={testID ? `${testID}-icon-right` : undefined}
size={20}
color={colors.fontDefault}
style={[styles.iconContainer, styles.iconRight]}
accessible={false}
/>
) : null}
{iconRight && !showClearInput ? (
<CustomIcon
name={iconRight}
testID={testID ? `${testID}-icon-right` : undefined}
size={20}
color={colors.fontDefault}
style={[styles.iconContainer, styles.iconRight]}
accessible={false}
/>
) : null}

{secureTextEntry ? (
<Touchable
style={[styles.iconContainer, styles.iconRight]}
accessible
accessibilityLabel={showPassword ? i18n.t('Hide_Password') : i18n.t('Show_Password')}
onPress={() => setShowPassword(!showPassword)}>
<CustomIcon
name={showPassword ? 'unread-on-top' : 'unread-on-top-disabled'}
testID={testID ? `${testID}-icon-password` : undefined}
size={20}
color={colors.fontDefault}
/>
</Touchable>
) : null}
{secureTextEntry ? (
<A11yElement order={2} style={[styles.iconContainer, styles.iconRight]}>
<Touchable
accessible
accessibilityLabel={showPassword ? i18n.t('Hide_Password') : i18n.t('Show_Password')}
onPress={() => setShowPassword(!showPassword)}>
<CustomIcon
name={showPassword ? 'unread-on-top' : 'unread-on-top-disabled'}
testID={testID ? `${testID}-icon-password` : undefined}
size={20}
color={colors.fontDefault}
/>
</Touchable>
</A11yElement>
) : null}

{loading ? (
<ActivityIndicator
style={[styles.iconContainer, styles.iconRight]}
color={colors.fontDefault}
testID={testID ? `${testID}-loading` : undefined}
/>
) : null}
{left}
</View>
{error && error.reason ? <Text style={[styles.error, { color: colors.fontDanger }]}>{error.reason}</Text> : null}
</View>
{loading ? (
<ActivityIndicator
style={[styles.iconContainer, styles.iconRight]}
color={colors.fontDefault}
testID={testID ? `${testID}-loading` : undefined}
/>
) : null}
{left}
</View>
{error && error.reason ? <Text style={[styles.error, { color: colors.fontDanger }]}>{error.reason}</Text> : null}
</View>
</A11yElement>
</A11yContainer>
);
};
4 changes: 4 additions & 0 deletions ios/A11yFlowModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#import <React/RCTBridgeModule.h>
@interface A11yFlowModule : NSObject <RCTBridgeModule>
@end

Loading