This commit is contained in:
120
react/features/base/ui/components/native/Button.tsx
Normal file
120
react/features/base/ui/components/native/Button.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StyleProp, TouchableHighlight } from 'react-native';
|
||||
import { Button as NativePaperButton, Text } from 'react-native-paper';
|
||||
import { IconSource } from 'react-native-paper/lib/typescript/components/Icon';
|
||||
|
||||
import { BUTTON_MODES, BUTTON_TYPES } from '../../constants.native';
|
||||
import BaseTheme from '../BaseTheme.native';
|
||||
import { IButtonProps } from '../types';
|
||||
|
||||
import styles from './buttonStyles';
|
||||
|
||||
|
||||
export interface IProps extends IButtonProps {
|
||||
color?: string | undefined;
|
||||
contentStyle?: Object | undefined;
|
||||
id?: string;
|
||||
labelStyle?: Object | undefined;
|
||||
mode?: any;
|
||||
style?: Object | undefined;
|
||||
}
|
||||
|
||||
const Button: React.FC<IProps> = ({
|
||||
accessibilityLabel,
|
||||
color: buttonColor,
|
||||
contentStyle,
|
||||
disabled,
|
||||
icon,
|
||||
id,
|
||||
labelKey,
|
||||
labelStyle,
|
||||
mode = BUTTON_MODES.CONTAINED,
|
||||
onClick: onPress,
|
||||
style,
|
||||
type
|
||||
}: IProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { DESTRUCTIVE, PRIMARY, SECONDARY, TERTIARY } = BUTTON_TYPES;
|
||||
const { CONTAINED, TEXT } = BUTTON_MODES;
|
||||
|
||||
let buttonLabelStyles;
|
||||
let buttonStyles;
|
||||
let color;
|
||||
|
||||
if (type === PRIMARY) {
|
||||
buttonLabelStyles = mode === TEXT
|
||||
? styles.buttonLabelPrimaryText
|
||||
: styles.buttonLabelPrimary;
|
||||
color = mode === CONTAINED && BaseTheme.palette.action01;
|
||||
} else if (type === SECONDARY) {
|
||||
buttonLabelStyles = styles.buttonLabelSecondary;
|
||||
color = mode === CONTAINED && BaseTheme.palette.action02;
|
||||
} else if (type === DESTRUCTIVE) {
|
||||
buttonLabelStyles = mode === TEXT
|
||||
? styles.buttonLabelDestructiveText
|
||||
: styles.buttonLabelDestructive;
|
||||
color = mode === CONTAINED && BaseTheme.palette.actionDanger;
|
||||
} else {
|
||||
color = buttonColor;
|
||||
buttonLabelStyles = styles.buttonLabel;
|
||||
}
|
||||
|
||||
if (disabled) {
|
||||
buttonLabelStyles = styles.buttonLabelDisabled;
|
||||
buttonStyles = styles.buttonDisabled;
|
||||
} else {
|
||||
buttonStyles = styles.button;
|
||||
}
|
||||
|
||||
if (type === TERTIARY) {
|
||||
if (disabled) {
|
||||
buttonLabelStyles = styles.buttonLabelTertiaryDisabled;
|
||||
}
|
||||
buttonLabelStyles = styles.buttonLabelTertiary;
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
accessibilityLabel = { accessibilityLabel }
|
||||
disabled = { disabled }
|
||||
id = { id }
|
||||
onPress = { onPress }
|
||||
style = { [
|
||||
buttonStyles,
|
||||
style
|
||||
] as StyleProp<object> }>
|
||||
<Text
|
||||
style = { [
|
||||
buttonLabelStyles,
|
||||
labelStyle
|
||||
] as StyleProp<object> }>{ t(labelKey ?? '') }</Text>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<NativePaperButton
|
||||
accessibilityLabel = { t(accessibilityLabel ?? '') }
|
||||
buttonColor = { color }
|
||||
children = { t(labelKey ?? '') }
|
||||
contentStyle = { [
|
||||
styles.buttonContent,
|
||||
contentStyle
|
||||
] as StyleProp<object> }
|
||||
disabled = { disabled }
|
||||
icon = { icon as IconSource | undefined }
|
||||
id = { id }
|
||||
labelStyle = { [
|
||||
buttonLabelStyles,
|
||||
labelStyle
|
||||
] as StyleProp<object> }
|
||||
mode = { mode }
|
||||
onPress = { onPress }
|
||||
style = { [
|
||||
buttonStyles,
|
||||
style
|
||||
] as StyleProp<object> } />
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
||||
71
react/features/base/ui/components/native/IconButton.tsx
Normal file
71
react/features/base/ui/components/native/IconButton.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import React from 'react';
|
||||
import { TouchableHighlight, ViewStyle } from 'react-native';
|
||||
|
||||
import Icon from '../../../icons/components/Icon';
|
||||
import styles from '../../../react/components/native/styles';
|
||||
import { IIconButtonProps } from '../../../react/types';
|
||||
import { BUTTON_TYPES } from '../../constants.native';
|
||||
import BaseTheme from '../BaseTheme.native';
|
||||
|
||||
|
||||
const IconButton: React.FC<IIconButtonProps> = ({
|
||||
accessibilityLabel,
|
||||
color: iconColor,
|
||||
disabled,
|
||||
id,
|
||||
onPress,
|
||||
size,
|
||||
src,
|
||||
style,
|
||||
tapColor,
|
||||
type
|
||||
}: IIconButtonProps) => {
|
||||
const { PRIMARY, SECONDARY, TERTIARY } = BUTTON_TYPES;
|
||||
|
||||
let color;
|
||||
let underlayColor;
|
||||
let iconButtonContainerStyles;
|
||||
|
||||
if (type === PRIMARY) {
|
||||
color = BaseTheme.palette.icon01;
|
||||
iconButtonContainerStyles = styles.iconButtonContainerPrimary;
|
||||
underlayColor = BaseTheme.palette.action01;
|
||||
} else if (type === SECONDARY) {
|
||||
color = BaseTheme.palette.icon04;
|
||||
iconButtonContainerStyles = styles.iconButtonContainerSecondary;
|
||||
underlayColor = BaseTheme.palette.action02;
|
||||
} else if (type === TERTIARY) {
|
||||
color = iconColor;
|
||||
iconButtonContainerStyles = styles.iconButtonContainer;
|
||||
underlayColor = BaseTheme.palette.action03;
|
||||
} else {
|
||||
color = iconColor;
|
||||
underlayColor = tapColor;
|
||||
}
|
||||
|
||||
if (disabled) {
|
||||
color = BaseTheme.palette.icon03;
|
||||
iconButtonContainerStyles = styles.iconButtonContainerDisabled;
|
||||
underlayColor = 'transparent';
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
accessibilityLabel = { accessibilityLabel }
|
||||
disabled = { disabled }
|
||||
id = { id }
|
||||
onPress = { onPress }
|
||||
style = { [
|
||||
iconButtonContainerStyles,
|
||||
style
|
||||
] as ViewStyle[] }
|
||||
underlayColor = { underlayColor }>
|
||||
<Icon
|
||||
color = { color }
|
||||
size = { size ?? 20 }
|
||||
src = { src } />
|
||||
</TouchableHighlight>
|
||||
);
|
||||
};
|
||||
|
||||
export default IconButton;
|
||||
197
react/features/base/ui/components/native/Input.tsx
Normal file
197
react/features/base/ui/components/native/Input.tsx
Normal file
@@ -0,0 +1,197 @@
|
||||
import React, { forwardRef, useCallback, useState } from 'react';
|
||||
import {
|
||||
KeyboardTypeOptions,
|
||||
NativeSyntheticEvent,
|
||||
ReturnKeyTypeOptions,
|
||||
StyleProp,
|
||||
Text,
|
||||
TextInput,
|
||||
TextInputChangeEventData,
|
||||
TextInputFocusEventData,
|
||||
TextInputKeyPressEventData,
|
||||
TextInputSubmitEditingEventData,
|
||||
TextStyle,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
ViewStyle
|
||||
} from 'react-native';
|
||||
|
||||
import Icon from '../../../icons/components/Icon';
|
||||
import { IconCloseCircle } from '../../../icons/svg';
|
||||
import BaseTheme from '../../../ui/components/BaseTheme.native';
|
||||
import { IInputProps } from '../types';
|
||||
|
||||
import styles from './inputStyles';
|
||||
|
||||
interface IProps extends IInputProps {
|
||||
accessibilityLabel?: any;
|
||||
autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters' | undefined;
|
||||
autoFocus?: boolean;
|
||||
blurOnSubmit?: boolean | undefined;
|
||||
bottomLabel?: string;
|
||||
customStyles?: ICustomStyles;
|
||||
editable?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* The id to set on the input element.
|
||||
* This is required because we need it internally to tie the input to its
|
||||
* info (label, error) so that screen reader users don't get lost.
|
||||
*/
|
||||
id?: string;
|
||||
keyboardType?: KeyboardTypeOptions;
|
||||
maxLength?: number | undefined;
|
||||
minHeight?: number | string | undefined;
|
||||
multiline?: boolean | undefined;
|
||||
numberOfLines?: number | undefined;
|
||||
onBlur?: ((e: NativeSyntheticEvent<TextInputFocusEventData>) => void) | undefined;
|
||||
onFocus?: ((e: NativeSyntheticEvent<TextInputFocusEventData>) => void) | undefined;
|
||||
onKeyPress?: ((e: NativeSyntheticEvent<TextInputKeyPressEventData>) => void) | undefined;
|
||||
onSubmitEditing?: (value: string) => void;
|
||||
pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined;
|
||||
returnKeyType?: ReturnKeyTypeOptions | undefined;
|
||||
secureTextEntry?: boolean | undefined;
|
||||
textContentType?: any;
|
||||
}
|
||||
|
||||
interface ICustomStyles {
|
||||
container?: Object;
|
||||
input?: Object;
|
||||
}
|
||||
|
||||
const Input = forwardRef<TextInput, IProps>(({
|
||||
accessibilityLabel,
|
||||
autoCapitalize,
|
||||
autoFocus,
|
||||
blurOnSubmit,
|
||||
bottomLabel,
|
||||
clearable,
|
||||
customStyles,
|
||||
disabled,
|
||||
error,
|
||||
icon,
|
||||
id,
|
||||
keyboardType,
|
||||
label,
|
||||
maxLength,
|
||||
minHeight,
|
||||
multiline,
|
||||
numberOfLines,
|
||||
onBlur,
|
||||
onChange,
|
||||
onFocus,
|
||||
onKeyPress,
|
||||
onSubmitEditing,
|
||||
placeholder,
|
||||
pointerEvents,
|
||||
returnKeyType,
|
||||
secureTextEntry,
|
||||
textContentType,
|
||||
value
|
||||
}: IProps, ref) => {
|
||||
const [ focused, setFocused ] = useState(false);
|
||||
const handleChange = useCallback((e: NativeSyntheticEvent<TextInputChangeEventData>) => {
|
||||
const { nativeEvent: { text } } = e;
|
||||
|
||||
onChange?.(text);
|
||||
}, [ onChange ]);
|
||||
|
||||
const clearInput = useCallback(() => {
|
||||
onChange?.('');
|
||||
}, [ onChange ]);
|
||||
|
||||
const handleBlur = useCallback((e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||
setFocused(false);
|
||||
onBlur?.(e);
|
||||
}, [ onBlur ]);
|
||||
|
||||
const handleFocus = useCallback((e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||
setFocused(true);
|
||||
onFocus?.(e);
|
||||
}, [ onFocus ]);
|
||||
|
||||
const handleKeyPress = useCallback((e: NativeSyntheticEvent<TextInputKeyPressEventData>) => {
|
||||
onKeyPress?.(e);
|
||||
}, [ onKeyPress ]);
|
||||
|
||||
const handleSubmitEditing = useCallback((e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => {
|
||||
const { nativeEvent: { text } } = e;
|
||||
|
||||
onSubmitEditing?.(text);
|
||||
}, [ onSubmitEditing ]);
|
||||
|
||||
return (<View style = { [ styles.inputContainer, customStyles?.container ] as StyleProp<ViewStyle> }>
|
||||
{label && <Text style = { styles.label }>{ label }</Text>}
|
||||
<View style = { styles.fieldContainer as StyleProp<ViewStyle> }>
|
||||
{icon && <Icon
|
||||
size = { 22 }
|
||||
src = { icon }
|
||||
style = { styles.icon } />}
|
||||
<TextInput
|
||||
accessibilityLabel = { accessibilityLabel }
|
||||
autoCapitalize = { autoCapitalize }
|
||||
autoComplete = { 'off' }
|
||||
autoCorrect = { false }
|
||||
autoFocus = { autoFocus }
|
||||
blurOnSubmit = { blurOnSubmit }
|
||||
editable = { !disabled }
|
||||
id = { id }
|
||||
keyboardType = { keyboardType }
|
||||
maxLength = { maxLength }
|
||||
|
||||
// @ts-ignore
|
||||
minHeight = { minHeight }
|
||||
multiline = { multiline }
|
||||
numberOfLines = { numberOfLines }
|
||||
onBlur = { handleBlur }
|
||||
onChange = { handleChange }
|
||||
onFocus = { handleFocus }
|
||||
onKeyPress = { handleKeyPress }
|
||||
onSubmitEditing = { handleSubmitEditing }
|
||||
placeholder = { placeholder }
|
||||
placeholderTextColor = { BaseTheme.palette.text02 }
|
||||
pointerEvents = { pointerEvents }
|
||||
ref = { ref }
|
||||
returnKeyType = { returnKeyType }
|
||||
secureTextEntry = { secureTextEntry }
|
||||
spellCheck = { false }
|
||||
style = { [
|
||||
styles.input,
|
||||
clearable && styles.clearableInput,
|
||||
customStyles?.input,
|
||||
disabled && styles.inputDisabled,
|
||||
icon && styles.iconInput,
|
||||
multiline && styles.inputMultiline,
|
||||
focused && styles.inputFocused,
|
||||
error && styles.inputError
|
||||
] as StyleProp<TextStyle> }
|
||||
textContentType = { textContentType }
|
||||
value = { typeof value === 'number' ? `${value}` : value } />
|
||||
{ clearable && !disabled && value !== '' && (
|
||||
<TouchableOpacity
|
||||
onPress = { clearInput }
|
||||
style = { styles.clearButton as StyleProp<ViewStyle> }>
|
||||
<Icon
|
||||
size = { 22 }
|
||||
src = { IconCloseCircle }
|
||||
style = { styles.clearIcon } />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
{
|
||||
bottomLabel && (
|
||||
<View>
|
||||
<Text
|
||||
id = { `${id}-description` }
|
||||
style = { [
|
||||
styles.bottomLabel,
|
||||
error && styles.bottomLabelError
|
||||
] }>
|
||||
{ bottomLabel }
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
</View>);
|
||||
});
|
||||
|
||||
export default Input;
|
||||
60
react/features/base/ui/components/native/Switch.tsx
Normal file
60
react/features/base/ui/components/native/Switch.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import React from 'react';
|
||||
import { ColorValue, StyleProp } from 'react-native';
|
||||
import { Switch as NativeSwitch } from 'react-native-paper';
|
||||
|
||||
import { ISwitchProps } from '../types';
|
||||
|
||||
import {
|
||||
DISABLED_TRACK_COLOR,
|
||||
ENABLED_TRACK_COLOR,
|
||||
THUMB_COLOR
|
||||
} from './switchStyles';
|
||||
|
||||
interface IProps extends ISwitchProps {
|
||||
|
||||
/**
|
||||
* Id for the switch.
|
||||
*/
|
||||
|
||||
id?: string;
|
||||
|
||||
/**
|
||||
* Custom styles for the switch.
|
||||
*/
|
||||
style?: Object;
|
||||
|
||||
/**
|
||||
* Color of the switch button.
|
||||
*/
|
||||
thumbColor?: ColorValue;
|
||||
|
||||
/**
|
||||
* Color of the switch background.
|
||||
*/
|
||||
trackColor?: Object;
|
||||
}
|
||||
|
||||
const Switch = ({
|
||||
checked,
|
||||
disabled,
|
||||
id,
|
||||
onChange,
|
||||
thumbColor = THUMB_COLOR,
|
||||
trackColor = {
|
||||
true: ENABLED_TRACK_COLOR,
|
||||
false: DISABLED_TRACK_COLOR
|
||||
},
|
||||
style
|
||||
}: IProps) => (
|
||||
<NativeSwitch
|
||||
disabled = { disabled }
|
||||
id = { id }
|
||||
ios_backgroundColor = { DISABLED_TRACK_COLOR }
|
||||
onValueChange = { onChange }
|
||||
style = { style as StyleProp<object> }
|
||||
thumbColor = { thumbColor }
|
||||
trackColor = { trackColor }
|
||||
value = { checked } />
|
||||
);
|
||||
|
||||
export default Switch;
|
||||
76
react/features/base/ui/components/native/buttonStyles.ts
Normal file
76
react/features/base/ui/components/native/buttonStyles.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import BaseTheme from '../../../ui/components/BaseTheme.native';
|
||||
|
||||
const BUTTON_HEIGHT = BaseTheme.spacing[7];
|
||||
|
||||
const button = {
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
display: 'flex',
|
||||
height: BUTTON_HEIGHT,
|
||||
justifyContent: 'center'
|
||||
};
|
||||
|
||||
const buttonLabel = {
|
||||
...BaseTheme.typography.bodyShortBold
|
||||
};
|
||||
|
||||
export default {
|
||||
button: {
|
||||
...button
|
||||
},
|
||||
|
||||
buttonLabel: {
|
||||
...buttonLabel
|
||||
},
|
||||
|
||||
buttonLabelDisabled: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.text03
|
||||
},
|
||||
|
||||
buttonContent: {
|
||||
height: BUTTON_HEIGHT
|
||||
},
|
||||
|
||||
buttonDisabled: {
|
||||
...button,
|
||||
backgroundColor: BaseTheme.palette.ui08
|
||||
},
|
||||
|
||||
buttonLabelPrimary: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.text01
|
||||
},
|
||||
|
||||
buttonLabelPrimaryText: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.action01
|
||||
},
|
||||
|
||||
buttonLabelSecondary: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.text04
|
||||
},
|
||||
|
||||
buttonLabelDestructive: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.text01
|
||||
},
|
||||
|
||||
buttonLabelDestructiveText: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.actionDanger
|
||||
},
|
||||
|
||||
buttonLabelTertiary: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.text01,
|
||||
marginHorizontal: BaseTheme.spacing[2],
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
buttonLabelTertiaryDisabled: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.text03,
|
||||
textAlign: 'center'
|
||||
}
|
||||
};
|
||||
87
react/features/base/ui/components/native/inputStyles.ts
Normal file
87
react/features/base/ui/components/native/inputStyles.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import BaseTheme from '../../../ui/components/BaseTheme.native';
|
||||
|
||||
export default {
|
||||
inputContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
},
|
||||
|
||||
label: {
|
||||
...BaseTheme.typography.bodyShortRegularLarge,
|
||||
lineHeight: 0,
|
||||
color: BaseTheme.palette.text01,
|
||||
marginBottom: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
fieldContainer: {
|
||||
position: 'relative'
|
||||
},
|
||||
|
||||
icon: {
|
||||
position: 'absolute',
|
||||
zIndex: 1,
|
||||
top: 14,
|
||||
left: 14
|
||||
},
|
||||
|
||||
input: {
|
||||
...BaseTheme.typography.bodyShortRegularLarge,
|
||||
backgroundColor: BaseTheme.palette.ui03,
|
||||
borderColor: BaseTheme.palette.ui03,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
borderWidth: 2,
|
||||
color: BaseTheme.palette.text01,
|
||||
paddingHorizontal: BaseTheme.spacing[3],
|
||||
height: BaseTheme.spacing[7],
|
||||
lineHeight: 20
|
||||
},
|
||||
|
||||
inputDisabled: {
|
||||
color: BaseTheme.palette.text03
|
||||
},
|
||||
|
||||
inputFocused: {
|
||||
borderColor: BaseTheme.palette.focus01
|
||||
},
|
||||
|
||||
inputError: {
|
||||
borderColor: BaseTheme.palette.textError
|
||||
},
|
||||
|
||||
iconInput: {
|
||||
paddingLeft: BaseTheme.spacing[6]
|
||||
},
|
||||
|
||||
inputMultiline: {
|
||||
height: BaseTheme.spacing[10],
|
||||
paddingTop: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
clearableInput: {
|
||||
paddingRight: BaseTheme.spacing[6]
|
||||
},
|
||||
|
||||
clearButton: {
|
||||
backgroundColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 14,
|
||||
width: BaseTheme.spacing[6],
|
||||
height: BaseTheme.spacing[7]
|
||||
},
|
||||
|
||||
clearIcon: {
|
||||
color: BaseTheme.palette.icon01
|
||||
},
|
||||
|
||||
bottomLabel: {
|
||||
...BaseTheme.typography.labelRegular,
|
||||
color: BaseTheme.palette.text02,
|
||||
marginTop: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
bottomLabelError: {
|
||||
color: BaseTheme.palette.textError
|
||||
}
|
||||
};
|
||||
5
react/features/base/ui/components/native/switchStyles.ts
Normal file
5
react/features/base/ui/components/native/switchStyles.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import BaseTheme from '../BaseTheme.native';
|
||||
|
||||
export const ENABLED_TRACK_COLOR = BaseTheme.palette.action01;
|
||||
export const DISABLED_TRACK_COLOR = BaseTheme.palette.ui05;
|
||||
export const THUMB_COLOR = BaseTheme.palette.icon01;
|
||||
Reference in New Issue
Block a user