init
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
2025-09-02 14:49:16 +08:00
commit 38ba663466
2885 changed files with 391107 additions and 0 deletions

View 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;

View 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;

View 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;

View 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;

View 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'
}
};

View 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
}
};

View 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;