react-native#LayoutRectangle TypeScript Examples
The following examples show how to use
react-native#LayoutRectangle.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: AspectRatio.tsx From react-native-jigsaw with MIT License | 6 votes |
AspectRatio: React.FC<Props> = (props) => {
const [layout, setLayout] = React.useState<LayoutRectangle | null>(null);
const { aspectRatio = 1, ...inputStyle } =
StyleSheet.flatten(props.style) || {};
const style = [inputStyle, { aspectRatio }];
if (layout) {
const { width = 0, height = 0 } = layout;
if (width === 0) {
style.push({ width: height * (1 / aspectRatio), height });
} else {
style.push({ width, height: width * (1 / aspectRatio) });
}
}
return (
<View
{...props}
style={style}
onLayout={({ nativeEvent: { layout: l } }) => setLayout(l)}
>
{props.children}
</View>
);
}
Example #2
Source File: NativeLinearGradient.web.tsx From nlw2-proffy with MIT License | 5 votes |
NativeLinearGradient: FunctionComponent<Props> = ({
colors,
locations,
startPoint,
endPoint,
...props
}: Props) => {
const [layout, setLayout] = useState<LayoutRectangle | null>(null);
const [gradientColors, setGradientColors] = useState<string[]>([]);
const [pseudoAngle, setPseudoAngle] = useState<number>(0);
const { width = 1, height = 1 } = layout ?? {};
useEffect(() => {
const getControlPoints = (): Point[] => {
let correctedStartPoint: Point = [0, 0];
if (Array.isArray(startPoint)) {
correctedStartPoint = [
startPoint[0] != null ? startPoint[0] : 0.0,
startPoint[1] != null ? startPoint[1] : 0.0,
];
}
let correctedEndPoint: Point = [0.0, 1.0];
if (Array.isArray(endPoint)) {
correctedEndPoint = [
endPoint[0] != null ? endPoint[0] : 0.0,
endPoint[1] != null ? endPoint[1] : 1.0,
];
}
return [correctedStartPoint, correctedEndPoint];
};
const [start, end] = getControlPoints();
start[0] *= width;
end[0] *= width;
start[1] *= height;
end[1] *= height;
const py = end[1] - start[1];
const px = end[0] - start[0];
setPseudoAngle(90 + (Math.atan2(py, px) * 180) / Math.PI);
}, [width, height, startPoint, endPoint]);
useEffect(() => {
const nextGradientColors = colors.map((color: number, index: number): string => {
const hexColor = normalizeColor(color);
let output = hexColor;
if (locations && locations[index]) {
const location = Math.max(0, Math.min(1, locations[index]));
// Convert 0...1 to 0...100
const percentage = location * 100;
output += ` ${percentage}%`;
}
return output;
});
setGradientColors(nextGradientColors);
}, [colors, locations]);
const colorStyle = gradientColors.join(',');
const backgroundImage = `linear-gradient(${pseudoAngle}deg, ${colorStyle})`;
// TODO: Bacon: In the future we could consider adding `backgroundRepeat: "no-repeat"`. For more
// browser support.
return (
<View
{...props}
style={[
props.style,
// @ts-ignore: [ts] Property 'backgroundImage' does not exist on type 'ViewStyle'.
{ backgroundImage },
]}
onLayout={event => {
setLayout(event.nativeEvent.layout);
if (props.onLayout) {
props.onLayout(event);
}
}}
/>
);
}
Example #3
Source File: Onboarding.tsx From mobile with Apache License 2.0 | 4 votes |
OnboardingScreen = () => {
const [i18n] = useI18n();
const [currentIndex, setCurrentIndex] = useState(0);
const carouselRef = useRef(null);
const {setOnboarded} = useStorage();
const navigation = useNavigation();
const startExposureNotificationService = useStartExposureNotificationService();
const handlePermissions = useCallback(async () => {
setOnboarded(true);
navigation.reset({
index: 0,
routes: [{name: 'Home'}],
});
await startExposureNotificationService();
}, [navigation, setOnboarded, startExposureNotificationService]);
const maxWidth = useMaxContentWidth();
const renderItem = useCallback(
({item}: {item: ViewKey}) => {
const ItemComponent = viewComponents[item];
return (
<Box maxWidth={maxWidth} alignSelf="center">
<ItemComponent />
</Box>
);
},
[maxWidth],
);
const nextItem = useCallback(() => {
if (carouselRef.current) {
if (currentIndex === contentData.length - 1) {
handlePermissions();
return;
}
(carouselRef.current! as CarouselStatic<ViewKey>).snapToNext();
}
}, [currentIndex, handlePermissions]);
const prevItem = useCallback(() => {
if (carouselRef.current) {
(carouselRef.current! as CarouselStatic<ViewKey>).snapToPrev();
}
}, []);
const isStart = currentIndex === 0;
const isEnd = currentIndex === contentData.length - 1;
const BackButton = <Button text={i18n.translate('Onboarding.ActionBack')} variant="subduedText" onPress={prevItem} />;
const LanguageButton = <LanguageToggle />;
const [layout, setLayout] = useState<LayoutRectangle | undefined>();
const onLayout = useCallback(({nativeEvent: {layout}}: LayoutChangeEvent) => {
setLayout(layout);
}, []);
return (
<Box flex={1} backgroundColor="overlayBackground">
<SafeAreaView style={styles.flex}>
<Header isOverlay />
<Box flex={1} justifyContent="center" onLayout={onLayout}>
{layout && (
<Carousel
ref={carouselRef}
data={contentData}
renderItem={renderItem}
sliderWidth={layout.width}
itemWidth={layout.width}
itemHeight={layout.height}
onSnapToItem={newIndex => setCurrentIndex(newIndex)}
/>
)}
</Box>
<Box flexDirection="row" padding="l">
<Box flex={1}>{isStart ? LanguageButton : BackButton}</Box>
<Box flex={1} justifyContent="center">
<ProgressCircles alignSelf="center" numberOfSteps={contentData.length} activeStep={currentIndex + 1} />
</Box>
<Box flex={1}>
<Button
text={i18n.translate(`Onboarding.Action${isEnd ? 'End' : 'Next'}`)}
variant="text"
onPress={nextItem}
/>
</Box>
</Box>
</SafeAreaView>
</Box>
);
}
Example #4
Source File: Chip.tsx From react-native-design-kit with MIT License | 4 votes |
export default function Chip({
actionType = 'chip',
containerStyle,
chips,
chipContainerStyle,
chipComponent,
chipTitleStyle,
selectedChipContainerStyle,
selectedChipTitleStyle,
horizontal,
horizontalScrollIndicator = false,
horizontalScrollEnabled = true,
horizontalScrollButton = true,
horizontalScrollLeftButton,
horizontalScrollLeftButtonContainerStyle,
horizontalScrollRightButton,
horizontalScrollRightButtonContainerStyle,
selectedId,
leftIcon,
leftIconAction,
rightIcon,
rightIconAction,
onSelect,
onPress,
...props
}: ChipProps) {
const singleValue = useMemo(() => actionType === 'radio', [actionType]);
const [chipIds, setChipIds] = useState(chips);
const [layout, setLayout] = useState<LayoutRectangle>();
const [size, setSize] = useState<NativeScrollPoint>();
const [offset, setOffset] = useState<NativeScrollPoint>({x: 0, y: 0});
const [selected, setSelected] = useState<string[]>(
filterSelectList(chipIds, selectedId || [], singleValue),
);
const refScroll = useRef<FlatList<string>>();
const initialize = useRef(false);
const difSize = useMemo(
() => (layout && size ? size.x - layout.width : undefined),
[layout],
);
const allowScrollLeft = useMemo(() => offset !== undefined && offset.x > 0, [
offset,
]);
const allowScrollRight = useMemo(
() => difSize !== undefined && offset.x < difSize,
[difSize, offset],
);
const isSelected = useCallback((id: string) => selected.indexOf(id) >= 0, [
selected,
]);
const removeChipId = useCallback(
(id: string) => setChipIds(chipIds.filter(chipId => chipId !== id)),
[chipIds],
);
const getIconAction = useCallback(
(id: string, iconActionFunction?: ChipIconAction) => {
if (iconActionFunction) {
const action = iconActionFunction(id, isSelected(id));
if (action === 'delete') {
return () => removeChipId(id);
} else if (action === 'check') {
return undefined;
}
return action;
}
return undefined;
},
[isSelected],
);
const handleRefList = useCallback((instance: FlatList<string>) => {
if (instance) {
refScroll.current = instance;
}
}, []);
const handlePressChipItem = useCallback(
(id: string, event: GestureResponderEvent) => {
onPress && onPress(event);
if (actionType !== 'chip') {
if (actionType === 'checkbox') {
const selection = [...selected];
if (isSelected(id)) {
selection.splice(selection.indexOf(id), 1);
} else {
selection.push(id);
}
setSelected(selection);
onSelect(id, selection);
} else {
const selection = [id];
setSelected([id]);
onSelect(id, selection);
}
} else {
onSelect(id, selected);
}
},
[actionType, selected, isSelected, onPress, onSelect],
);
const handlePressScrollLeftButton = useCallback(
() =>
refScroll.current &&
refScroll.current.scrollToOffset({
offset: Math.max(0, offset.x - 125),
animated: true,
}),
[refScroll.current, offset],
);
const handlePressScrollRightButton = useCallback(
() =>
refScroll.current &&
difSize &&
refScroll.current.scrollToOffset({
offset: Math.min(difSize, offset.x + 125),
animated: true,
}),
[refScroll.current, difSize, offset],
);
const handleRenderIcon = useCallback(
(
id: string,
iconFunction?: ChipIcon,
iconActionFunction?: ChipIconAction,
) => {
if (iconFunction) {
return iconFunction({id, isSelected: isSelected(id)});
}
if (iconActionFunction) {
const action = iconActionFunction(id, isSelected(id));
if (action === 'delete') {
return (
<Icon
testID="icon-delete"
style={styles.icon}
name="times-circle"
/>
);
} else if (action === 'check' && isSelected(id)) {
return (
<Icon
style={StyleSheet.flatten([styles.icon, styles.iconCheck])}
name="check"
/>
);
}
}
return undefined;
},
[isSelected],
);
const handleRenderChipItem = useCallback(
(id: string) => {
const component =
chipComponent && chipComponent({id, isSelected: isSelected(id)});
const title =
typeof component === 'string'
? component
: component === undefined
? id
: undefined;
return (
<ChipItem
{...props}
key={id}
containerStyle={StyleSheet.flatten([
typeof chipContainerStyle === 'function'
? chipContainerStyle(id)
: chipContainerStyle,
isSelected(id)
? StyleSheet.flatten([
styles.selectedChipContainer,
typeof selectedChipContainerStyle === 'function'
? selectedChipContainerStyle(id)
: selectedChipContainerStyle,
])
: {},
])}
title={title}
titleStyle={StyleSheet.flatten([
typeof chipTitleStyle === 'function'
? chipTitleStyle(id)
: chipTitleStyle,
isSelected(id)
? typeof selectedChipTitleStyle === 'function'
? selectedChipTitleStyle(id)
: selectedChipTitleStyle
: {},
])}
leftIcon={handleRenderIcon(id, leftIcon, leftIconAction)}
leftIconAction={getIconAction(id, leftIconAction)}
rightIcon={handleRenderIcon(id, rightIcon, rightIconAction)}
rightIconAction={getIconAction(id, rightIconAction)}
onPress={event => handlePressChipItem(id, event)}>
{component !== undefined &&
typeof component !== 'string' &&
component}
</ChipItem>
);
},
[
props,
chipTitleStyle,
chipContainerStyle,
selectedChipTitleStyle,
selectedChipContainerStyle,
leftIcon,
leftIconAction,
rightIcon,
rightIconAction,
chipComponent,
isSelected,
handleRenderIcon,
handlePressChipItem,
],
);
const handleRenderScrollLeftButton = useMemo(
() =>
horizontalScrollButton && (
<Touchable
testID="button-left"
disabled={!allowScrollLeft}
style={StyleSheet.flatten([
styles.scrollContainer,
styles.scrollLeftIconContainer,
horizontalScrollLeftButtonContainerStyle,
!allowScrollLeft ? styles.scrollContainerDisabled : {},
])}
onPress={handlePressScrollLeftButton}>
{horizontalScrollLeftButton || <Icon name="chevron-left" />}
</Touchable>
),
[
allowScrollLeft,
horizontalScrollButton,
horizontalScrollLeftButton,
horizontalScrollLeftButtonContainerStyle,
handlePressScrollLeftButton,
],
);
const handleRenderScrollRightButton = useMemo(() => {
return (
horizontalScrollButton && (
<Touchable
testID="button-right"
disabled={!allowScrollRight}
style={StyleSheet.flatten([
styles.scrollContainer,
styles.scrollRightIconContainer,
horizontalScrollRightButtonContainerStyle,
!allowScrollRight ? styles.scrollContainerDisabled : {},
])}
onPress={handlePressScrollRightButton}>
{horizontalScrollRightButton || <Icon name="chevron-right" />}
</Touchable>
)
);
}, [
allowScrollRight,
horizontalScrollButton,
horizontalScrollRightButton,
horizontalScrollRightButtonContainerStyle,
handlePressScrollRightButton,
]);
const handleRenderListChipItem = useMemo(
() => chipIds.map(id => handleRenderChipItem(id)),
[chipIds, handleRenderChipItem],
);
useEffect(() => {
setChipIds(chips);
}, [chips]);
useEffect(() => {
if (initialize.current) {
setSelected(filterSelectList(chipIds, selectedId || [], singleValue));
} else {
initialize.current = true;
}
}, [singleValue, chipIds, selectedId]);
return horizontal ? (
<View style={StyleSheet.flatten([containerStyle, styles.containerNoWrap])}>
{handleRenderScrollLeftButton}
<FlatList
horizontal
testID="list"
ref={handleRefList}
onLayout={event => setLayout(event.nativeEvent.layout)}
data={chipIds}
scrollEnabled={horizontalScrollEnabled}
onContentSizeChange={(w, h) => setSize({x: w, y: h})}
onScroll={event => setOffset(event.nativeEvent.contentOffset)}
contentContainerStyle={styles.sectionWrap}
showsHorizontalScrollIndicator={horizontalScrollIndicator}
keyExtractor={item => item}
renderItem={({item}) => handleRenderChipItem(item)}
/>
{handleRenderScrollRightButton}
</View>
) : (
<View style={StyleSheet.flatten([containerStyle, styles.containerWrap])}>
{handleRenderListChipItem}
</View>
);
}
Example #5
Source File: Input.tsx From react-native-design-kit with MIT License | 4 votes |
export default function Input({
containerStyle,
label,
labelStyle,
labelContainerStyle,
labelPosition = 'container',
inputContainerStyle,
inputRef,
leftIcon,
leftIconAction,
leftIconContainerStyle,
rightIcon,
rightIconAction,
rightIconContainerStyle,
focusStyle,
focusLabelStyle,
focusContainerStyle,
focusLabelContainerStyle,
focusInputContainerStyle,
focusLeftIconContainerStyle,
focusRightIconContainerStyle,
error,
errorStyle,
errorLabelStyle,
errorLabelContainerStyle,
errorContainerStyle,
errorInputContainerStyle,
errorLeftIconContainerStyle,
errorRightIconContainerStyle,
clearErrorOnFocus = false,
searchTimeout = 500,
onSearch,
strength,
strengthValidation = [/.{4}/, /.{8}/, /.{12}/],
strengthColor,
strengthContainerStyle,
strengthLeftContainerStyle,
strengthRightContainerStyle,
labelBoxStandBySize = 15,
labelBoxStandByOffset = 14,
labelBoxActiveSize = 12,
labelBoxActiveOffset = 1,
inputBoxActiveOffset = 6,
style,
placeholder,
multiline,
secureTextEntry,
onChangeText,
onFocus,
onBlur,
...props
}: InputProps) {
const [visibility, setVisibility] = useState(false);
const [errorMessage, setErrorMessage] = useState(getErrorMessage(undefined));
const [focus, setFocus] = useState(false);
const [inputValue, setInputValue] = useState(
props.value !== undefined ? props.value : props.defaultValue,
);
const [fillStatus, setFillStatus] = useState<InputFillStatus>(
inputValue !== undefined && inputValue.length > 0 ? 'filled' : 'empty',
);
const [inputSearch, setInputSearch] = useState<InputSearch>({
search: inputValue,
searchStatus:
inputValue !== undefined && inputValue.length ? 'loading' : 'empty',
});
const [layoutBorder, setLayoutBorder] = useState<LayoutRectangle>();
const [ref, setRef] = useState<TextInput>();
const [refBorder, setRefBorder] = useState<View>();
const {search, searchStatus} = inputSearch;
const themeBorderActive = inputValue !== undefined && inputValue !== '';
const animation = useState(new Animated.Value(themeBorderActive ? 1 : 0))[0];
const inputLeftIcon = getIcon(leftIcon, leftIconAction);
const inputRightIcon = getIcon(rightIcon, rightIconAction);
useEffect(() => {
setVisibility(!secureTextEntry);
}, [secureTextEntry]);
useEffect(() => {
setErrorMessage(getErrorMessage(inputValue));
}, [error]);
useEffect(() => {
if (
inputValue !== undefined &&
inputValue.length > 0 &&
fillStatus === 'empty'
) {
setFillStatus('filled');
} else if (
(inputValue === undefined || inputValue.length === 0) &&
fillStatus === 'filled'
) {
setFillStatus('empty');
}
Animated.spring(animation, {
toValue: inputValue !== undefined && inputValue !== '' ? 1 : 0,
bounciness: 0,
useNativeDriver: false,
}).start();
if (onSearch !== undefined) {
if (inputValue !== undefined && inputValue.length > 0) {
if (searchStatus !== 'loading') {
setInputSearch({search: undefined, searchStatus: 'loading'});
}
} else {
setInputSearch({search: undefined, searchStatus: 'empty'});
}
const timeout = setTimeout(() => {
onSearch(inputValue || '', handleSearch);
}, searchTimeout);
return () => clearTimeout(timeout);
}
}, [inputValue]);
useEffect(() => {
updateLayoutBorder();
}, [
label,
labelPosition,
labelContainerStyle,
focusLabelContainerStyle,
errorLabelContainerStyle,
]);
useEffect(() => {
if (
(searchStatus === 'allowed' || searchStatus === 'forbidden') &&
search !== inputValue
) {
setInputSearch({
search: undefined,
searchStatus:
inputValue !== undefined && inputValue.length > 0
? 'loading'
: 'empty',
});
}
}, [inputSearch]);
function handleSearch(text: string, allowed: boolean) {
setInputSearch({
search: text,
searchStatus: allowed ? 'allowed' : 'forbidden',
});
}
function getErrorMessage(text?: string) {
if (error !== undefined) {
if (typeof error === 'string') {
return error;
}
if (text !== undefined) {
if (Array.isArray(error)) {
for (let index = 0; index < error.length; index++) {
const result = getInputValidationError(error[index], text);
if (result !== undefined) {
return result;
}
}
} else {
return getInputValidationError(error, text);
}
}
}
return undefined;
}
function getInputValidationError(
inputValidation: InputValidation,
text: string,
) {
const regex = inputValidation.regex;
const validation = inputValidation.validation;
if (!regex?.test(text) || (validation && validation(text))) {
return inputValidation.error;
}
return undefined;
}
function updateLayoutBorder() {
labelPosition === 'border' &&
refBorder?.measure((x, y, width, height) => {
setLayoutBorder({
x: x,
y: y,
width: width,
height: height,
});
});
}
function getIcon(inputIcon?: InputIcon, inputIconAction?: InputIconAction) {
if (inputIconAction !== undefined) {
if (inputIconAction === 'delete') {
const iconDelete =
typeof inputIcon === 'function' ? inputIcon(fillStatus) : inputIcon;
if (iconDelete !== undefined) {
return iconDelete;
}
return fillStatus === 'filled' ? (
<Icon style={styles.icon} name="times-circle" />
) : (
undefined
);
} else if (inputIconAction === 'search') {
const iconSearch =
typeof inputIcon === 'function' ? inputIcon(searchStatus) : inputIcon;
if (iconSearch !== undefined) {
return iconSearch;
}
if (searchStatus === 'loading') {
return <ActivityIndicator />;
}
if (searchStatus === 'allowed') {
return (
<Icon
style={StyleSheet.flatten([
styles.icon,
styles.iconSearchAllowed,
])}
name="check"
/>
);
}
if (searchStatus === 'forbidden') {
return (
<Icon
style={StyleSheet.flatten([
styles.icon,
styles.iconSearchForbidden,
])}
name="close"
/>
);
}
return undefined;
} else if (inputIconAction === 'toggle-visibility') {
const iconVisibility =
typeof inputIcon === 'function'
? inputIcon(visibility ? 'visibile' : 'hidden')
: inputIcon;
if (iconVisibility !== undefined) {
return iconVisibility;
}
return (
<Icon style={styles.icon} name={visibility ? 'eye' : 'eye-slash'} />
);
}
}
return typeof inputIcon === 'function' ? inputIcon('normal') : inputIcon;
}
function getIconAction(
inputIconAction?: InputIconAction,
): (() => void) | undefined {
if (inputIconAction !== undefined) {
if (typeof inputIconAction === 'string') {
if (inputIconAction === 'delete') {
if (fillStatus === 'filled') {
return () => {
ref?.clear();
onChangeText && onChangeText('');
typeof error === 'object' &&
errorMessage !== undefined &&
setErrorMessage(getErrorMessage(''));
setInputValue('');
setFillStatus('empty');
};
}
} else if (inputIconAction === 'toggle-visibility') {
return () => setVisibility(!visibility);
}
} else {
return () => inputIconAction();
}
}
return undefined;
}
function passwordStrengthEstimator() {
let count = 0;
if (inputValue !== undefined && strengthValidation !== undefined) {
if (Array.isArray(strengthValidation)) {
for (let index = 0; index < strengthValidation.length; index++) {
const validation = strengthValidation[index];
if (typeof validation === 'function') {
if (validation(inputValue)) {
count++;
}
} else if (validation.test(inputValue)) {
count++;
}
}
} else {
if (typeof strengthValidation === 'function') {
strengthValidation(inputValue) && count++;
} else {
strengthValidation.test(inputValue) && count++;
}
}
}
return count;
}
function getStrengthColor() {
return strengthColor !== undefined
? strengthColor(passwordStrengthEstimator())
: 'green';
}
function getStrengthDeviation() {
if (strengthValidation !== undefined) {
if (Array.isArray(strengthValidation)) {
return strengthValidation.length - passwordStrengthEstimator();
} else {
return 1 - passwordStrengthEstimator();
}
}
return 1;
}
return (
<View
style={[styles.container, containerStyle, focus && focusContainerStyle]}>
{label !== undefined && labelPosition === 'container' ? (
<View
style={StyleSheet.flatten([
styles.labelContainerThemeContainer,
labelContainerStyle,
focus && focusLabelContainerStyle,
errorMessage !== undefined && errorLabelContainerStyle,
])}>
<Text
style={StyleSheet.flatten([
styles.label,
styles.labelThemeContainer,
labelStyle,
focus && focusLabelStyle,
errorMessage !== undefined && errorLabelStyle,
])}>
{label}
</Text>
</View>
) : (
<></>
)}
<View
style={[
styles.inputContainer,
inputContainerStyle,
focus && focusInputContainerStyle,
errorMessage !== undefined &&
StyleSheet.flatten([
styles.errorInputContainer,
errorInputContainerStyle,
]),
]}>
{inputLeftIcon && (
<View
style={[
styles.iconContainer,
styles.iconLeftContainer,
leftIconContainerStyle,
focus && focusLeftIconContainerStyle,
errorMessage !== undefined && errorLeftIconContainerStyle,
]}>
<TouchableWithoutFeedback onPress={getIconAction(leftIconAction)}>
{inputLeftIcon}
</TouchableWithoutFeedback>
</View>
)}
<View style={styles.sectionInputReverse}>
{inputRightIcon && (
<View
style={[
styles.iconContainer,
styles.iconRightContainer,
rightIconContainerStyle,
focus && focusRightIconContainerStyle,
errorMessage !== undefined && errorRightIconContainerStyle,
]}>
<TouchableWithoutFeedback
onPress={getIconAction(rightIconAction)}>
{inputRightIcon}
</TouchableWithoutFeedback>
</View>
)}
<View style={styles.sectionInputBox}>
{labelPosition === 'box' ? (
<Animated.View
style={StyleSheet.flatten([
styles.sectionLabelThemeBox,
focus && focusLabelContainerStyle,
errorMessage !== undefined && errorLabelContainerStyle,
{
top: animation.interpolate({
inputRange: [0, 1],
outputRange: [
labelBoxStandByOffset,
labelBoxActiveOffset,
],
}),
},
])}>
<Animated.Text
style={StyleSheet.flatten([
styles.label,
styles.labelThemeBox,
labelStyle,
focus && focusLabelStyle,
errorMessage !== undefined && errorLabelStyle,
{
fontSize: animation.interpolate({
inputRange: [0, 1],
outputRange: [labelBoxStandBySize, labelBoxActiveSize],
}),
},
props.placeholderTextColor !== undefined
? {
color: props.placeholderTextColor,
}
: {},
])}>
{label !== undefined ? label : placeholder}
</Animated.Text>
</Animated.View>
) : (
<></>
)}
<View
style={StyleSheet.flatten([
{height: '100%', width: '100%'},
labelPosition === 'box' &&
themeBorderActive && {paddingTop: inputBoxActiveOffset},
])}>
<TextInput
{...props}
ref={instance => {
if (instance && ref !== instance) {
inputRef && inputRef(instance);
setRef(instance);
}
}}
multiline={multiline}
secureTextEntry={!visibility}
placeholder={labelPosition === 'box' ? undefined : placeholder}
style={StyleSheet.flatten([
styles.inputBox,
multiline && styles.inputBoxMultiline,
style,
focus && focusStyle,
])}
onChangeText={text => {
onChangeText && onChangeText(text);
setInputValue(text);
}}
onFocus={event => {
onFocus && onFocus(event);
clearErrorOnFocus && setErrorMessage(undefined);
setFocus(true);
}}
onBlur={event => {
onBlur && onBlur(event);
setErrorMessage(getErrorMessage(inputValue || ''));
setFocus(false);
}}
/>
</View>
{label !== undefined && labelPosition === 'border' ? (
<View
ref={instance => instance && setRefBorder(instance)}
onLayout={() =>
layoutBorder === undefined && updateLayoutBorder()
}
style={[
styles.labelContainerThemeBorder,
labelContainerStyle,
focus && focusLabelContainerStyle,
errorMessage !== undefined &&
StyleSheet.flatten([
styles.errorLabelContainerThemeBorder,
errorLabelContainerStyle,
]),
styles.sectionLabelThemeBorder,
!layoutBorder && styles.labelContainerThemeBorderTransparent,
{
top: -1 + (layoutBorder ? -layoutBorder.height / 2 : 0),
},
]}>
<Text
style={StyleSheet.flatten([
styles.label,
styles.labelThemeBorder,
labelStyle,
focus && focusLabelStyle,
errorMessage !== undefined && errorLabelStyle,
])}>
{label}
</Text>
</View>
) : (
<></>
)}
</View>
</View>
</View>
{strength && (
<View
style={StyleSheet.flatten([
styles.strengthContainer,
strengthContainerStyle,
])}>
<View
style={StyleSheet.flatten([
styles.strengthLeftContainer,
strengthLeftContainerStyle,
{
flex: passwordStrengthEstimator(),
backgroundColor: getStrengthColor(),
},
])}
/>
<View
style={StyleSheet.flatten([
styles.strengthRightContainer,
strengthRightContainerStyle,
{
flex: getStrengthDeviation(),
},
])}
/>
</View>
)}
{errorMessage ? (
<View
style={StyleSheet.flatten([
styles.errorContainer,
errorContainerStyle,
])}>
<Text style={StyleSheet.flatten([styles.error, errorStyle])}>
{errorMessage}
</Text>
</View>
) : null}
</View>
);
}
Example #6
Source File: Slider.tsx From react-native-design-kit with MIT License | 4 votes |
export default function Slider({
containerStyle,
minValue = 0,
minTrackContainerStyle,
maxValue = 100,
maxTrackContainerStyle,
initialValue,
button,
buttonValue,
startButton,
startButtonContainerStyle,
endButton,
endButtonContainerStyle,
thumb,
thumbContainerStyle,
trackContainerStyle,
hitSlop = {top: 10, bottom: 10},
indicator,
indicatorStyle,
indicatorComponent,
indicatorSubStyle,
indicatorSubComponent,
indicatorContainerStyle,
numberOfSection = 10,
numberOfSubSection = 2,
onChangeValue,
}: SliderProps) {
const [progress, setProgress] = useState(
(initialValue !== undefined && getProgress(initialValue)) || 0.25,
);
const [startProgress, setStartProgress] = useState(progress);
const [thumbLayout, setThumbLayout] = useState<LayoutRectangle>();
const [pageX, setPageX] = useState<number>();
const [width, setWidth] = useState<number>();
const value = useMemo(() => progress * (maxValue - minValue) + minValue, [
progress,
maxValue,
minValue,
]);
function setValue(val: number) {
setProgress(getProgress(val));
}
function getProgress(val: number) {
return (
(Math.max(minValue, Math.min(maxValue, val)) - minValue) /
(maxValue - minValue)
);
}
const handleRenderIndicator = useMemo(() => {
const components: ReactElement[] = [];
for (let index = 0; index <= numberOfSection; index++) {
components.push(
<View key={`{indicatorSection: ${index}}`}>
{indicatorComponent || (
<View
style={StyleSheet.flatten([styles.indicator, indicatorStyle])}
/>
)}
</View>,
);
if (index < numberOfSection) {
for (let indexSub = 0; indexSub < numberOfSubSection - 1; indexSub++) {
components.push(
<View key={`{indicator: ${index}, sub: ${indexSub}}`}>
{indicatorSubComponent || (
<View
style={StyleSheet.flatten([
styles.indicator,
styles.indicatorSub,
indicatorSubStyle,
])}
/>
)}
</View>,
);
}
}
}
return components;
}, [
numberOfSection,
numberOfSubSection,
indicatorComponent,
indicatorSubComponent,
indicatorStyle,
indicatorSubStyle,
]);
const handlePressButtonLeft = useCallback(
() =>
setValue(
value -
(buttonValue !== undefined
? Math.max(0, buttonValue)
: (maxValue - minValue) * 0.15),
),
[value, buttonValue, maxValue, minValue],
);
const handlePressButtonRight = useCallback(
() =>
setValue(
value +
(buttonValue !== undefined
? Math.max(0, buttonValue)
: (maxValue - minValue) * 0.15),
),
[value, buttonValue, maxValue, minValue],
);
const handleResponderStart = useCallback(
(event: GestureResponderEvent) => {
if (width !== undefined) {
setPageX(event.nativeEvent.pageX);
setStartProgress(event.nativeEvent.locationX / width);
}
},
[width, progress],
);
const handleResponderMove = useCallback(
(event: GestureResponderEvent) => {
if (pageX !== undefined && width !== undefined) {
setProgress(
Math.max(
0,
Math.min(
1,
startProgress + (event.nativeEvent.pageX - pageX) / width,
),
),
);
}
},
[pageX, width],
);
const handleRenderButtonLeft = useMemo(
() =>
button && (
<Touchable
testID="button-start"
style={StyleSheet.flatten([
styles.startButtonContainer,
startButtonContainerStyle,
])}
onPress={handlePressButtonLeft}>
{startButton || <Icon style={styles.buttonIcon} name="caret-left" />}
</Touchable>
),
[button, startButtonContainerStyle, startButton, handlePressButtonLeft],
);
const handleRenderButtonRight = useMemo(
() =>
button && (
<Touchable
testID="button-end"
style={StyleSheet.flatten([
styles.endButtonContainer,
endButtonContainerStyle,
])}
onPress={handlePressButtonRight}>
{endButton || <Icon style={styles.buttonIcon} name="caret-right" />}
</Touchable>
),
[button, endButtonContainerStyle, endButton, handlePressButtonRight],
);
const handleRenderTopIndicator = useMemo(
() =>
indicator && (
<View
style={StyleSheet.flatten([
indicatorContainerStyle,
styles.sectionIndicator,
styles.sectionIndicatorTop,
])}>
{handleRenderIndicator}
</View>
),
[indicator, indicatorContainerStyle, handleRenderIndicator],
);
const handleRenderBottomIndicator = useMemo(
() =>
indicator && (
<View
style={StyleSheet.flatten([
indicatorContainerStyle,
styles.sectionIndicator,
styles.sectionIndicatorBottom,
])}>
{handleRenderIndicator}
</View>
),
[indicator, indicatorContainerStyle, handleRenderIndicator],
);
const handleRenderThumb = useMemo(
() =>
width ? (
<View
testID="thumb-container"
onLayout={event => setThumbLayout(event.nativeEvent.layout)}
style={StyleSheet.flatten([
styles.thumbContainer,
thumbContainerStyle,
styles.sectionThumb,
{
left:
progress * width - (thumbLayout ? thumbLayout.width / 2 : 0),
opacity: thumbLayout ? 1 : 0,
},
])}>
{thumb || <View style={styles.thumb} />}
</View>
) : null,
[thumb, thumbContainerStyle, width, progress, width, thumbLayout],
);
const handleRenderSlider = useMemo(
() => (
<View
testID="track-container"
style={styles.sectionTrackContainer}
pointerEvents="box-only"
onStartShouldSetResponder={() => true}
onResponderStart={handleResponderStart}
onResponderMove={handleResponderMove}
hitSlop={hitSlop}
onLayout={event => setWidth(event.nativeEvent.layout.width)}>
{handleRenderTopIndicator}
<View style={styles.sectionTrack}>
<View
style={StyleSheet.flatten([
styles.trackContainer,
trackContainerStyle,
styles.trackContainerMin,
minTrackContainerStyle,
{width: `${progress * 100}%`},
])}
/>
<View
style={StyleSheet.flatten([
styles.trackContainer,
trackContainerStyle,
styles.trackContainerMax,
maxTrackContainerStyle,
{width: `${(1 - progress) * 100}%`},
])}
/>
{handleRenderThumb}
</View>
{handleRenderBottomIndicator}
</View>
),
[
trackContainerStyle,
trackContainerStyle,
minTrackContainerStyle,
maxTrackContainerStyle,
progress,
handleRenderThumb,
handleRenderTopIndicator,
handleRenderBottomIndicator,
handleResponderStart,
handleResponderMove,
],
);
useDidUpdate(() => {
onChangeValue && onChangeValue(value, progress);
}, [value]);
return (
<View style={StyleSheet.flatten([styles.container, containerStyle])}>
{handleRenderButtonLeft}
{handleRenderSlider}
{handleRenderButtonRight}
</View>
);
}
Example #7
Source File: FrontSide.tsx From rn-credit-card with MIT License | 4 votes |
FrontSide: React.FC<Props> = ({ model, cardType, focusedField }) => {
const { overrides, translations, requiresName } = useContext(LibraryContext)
const [numberLayout, setNumberLayout] = useState<LayoutRectangle | null>(null)
const [nameLayout, setNameLayout] = useState<LayoutRectangle | null>(null)
const [
expirationLayout,
setExpirationLayout,
] = useState<LayoutRectangle | null>(null)
const { width: windowWidth } = useWindowDimensions()
const positionAnim = useRef(new Animated.ValueXY()).current
const sizeAnim = useRef(new Animated.ValueXY()).current
useEffect(() => {
function animate(layout: LayoutRectangle) {
Animated.spring(positionAnim, {
toValue: {
x: layout.x - 8,
y: layout.y,
},
useNativeDriver: false,
}).start()
Animated.spring(sizeAnim, {
toValue: {
x: layout.width + 16,
y: layout.height + 4,
},
useNativeDriver: false,
}).start()
}
if (focusedField === null) {
return
}
const layout = [numberLayout, nameLayout, expirationLayout][focusedField]
if (layout) {
animate(layout)
}
}, [
focusedField,
numberLayout,
nameLayout,
expirationLayout,
sizeAnim,
positionAnim,
])
return (
<>
<View style={styles.header}>
<CardIcon cardNumber={model.cardNumber} />
</View>
<PlaceholderText
style={[
styles.numberText,
{
fontSize: windowWidth < 390 ? 20 : 22,
},
overrides.cardPreview,
]}
value={model.cardNumber}
placeholder={
cardType === 'american-express'
? 'XXXX XXXXXX XXXXX'
: 'XXXX XXXX XXXX XXXX'
}
onLayout={({ nativeEvent }) => setNumberLayout(nativeEvent.layout)}
/>
<View style={styles.labelContainer}>
<Text style={[styles.labelText, overrides.labelText]}>
{requiresName ? translations.cardHolderName.toUpperCase() : ''}
</Text>
<Text style={[styles.labelText, overrides.labelText]}>
{translations.expiration}
</Text>
</View>
{requiresName && (
<Text
style={[
styles.bottomText,
styles.nameText,
{
color: model.holderName ? 'white' : 'gray',
},
overrides.cardHolderPreview,
]}
numberOfLines={1}
onLayout={({ nativeEvent }) => setNameLayout(nativeEvent.layout)}
>
{model.holderName.toUpperCase() || translations.nameSurname}
</Text>
)}
<PlaceholderText
style={[
styles.bottomText,
styles.expirationText,
overrides.expirationPreview,
]}
value={model.expiration}
placeholder={translations.mmYY}
onLayout={({ nativeEvent }) => setExpirationLayout(nativeEvent.layout)}
/>
<Animated.View
style={[
styles.outline,
{
left: positionAnim.x,
top: positionAnim.y,
width: sizeAnim.x,
height: sizeAnim.y,
},
overrides.outline,
]}
/>
</>
)
}
Example #8
Source File: AILabNativeImage.tsx From ai-lab with MIT License | 4 votes |
AILabNativeImage = ({
perf,
perfCallback,
source,
...props
}: AILabNativeImage) => {
const [imgDimensions, setImgDimensions] = useState<LayoutRectangle>({
height: 0,
width: 0,
x: 0,
y: 0,
});
const [isTFReady, setIsTFReady] = useState(false);
const [drawingTime, setDrawingTime] = useState(0);
const [perfProps, setPerfProps] = useState<PerformanceInfo>();
const canvasRef = useRef<Canvas>(null);
const modelPath =
'https://storage.googleapis.com/tfhub-tfjs-modules/tensorflow/tfjs-model/ssd_mobilenet_v2/1/default/1/model.json';
const tensorFlowIt = async (model: tf.GraphModel) => {
const imageURI = Image.resolveAssetSource(source).uri;
const response = await fetch(imageURI, {}, { isBinary: true });
const imageDataArrayBuffer = await response.arrayBuffer();
const imageData = new Uint8Array(imageDataArrayBuffer);
const { height, width } = imgDimensions;
const tensor = decodeJpeg(imageData)
.resizeBilinear([height, width])
.toInt();
// SSD Mobilenet single batch
const readyfied = tensor.expandDims();
const results = await model.executeAsync(readyfied);
const [detections, detectionAreas] = results as tf.Tensor<tf.Rank.R2>[];
// Prep Canvas
const canvas = canvasRef.current!;
const ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
ctx.font = '16px sans-serif';
ctx.textBaseline = 'top';
// Get a clean tensor of top indices
const detectionThreshold = 0.2;
const iouThreshold = 0.2;
// set to 0.1 to bring only 1 unbrella with beach.jpeg file
const maxBoxes = 20;
const prominentDetection = tf.topk(detections);
const justBoxes = detectionAreas.squeeze<tf.Tensor<tf.Rank.R2>>();
const justValues = prominentDetection.values.squeeze<
tf.Tensor<tf.Rank.R1>
>();
// Move results back to JavaScript in parallel
const [maxIndices, scores, boxes] = await Promise.all([
prominentDetection.indices.data(),
justValues.array(),
justBoxes.array(),
]);
// https://arxiv.org/pdf/1704.04503.pdf, use Async to keep visuals
const nmsDetections = await tf.image.nonMaxSuppressionWithScoreAsync(
justBoxes, // [numBoxes, 4]
justValues, // [numBoxes]
maxBoxes,
iouThreshold,
detectionThreshold,
1 // 0 is normal NMS, 1 is Soft-NMS for overlapping support
);
const chosen = await nmsDetections.selectedIndices.data();
// Mega Clean
tf.dispose([
(results as tf.Tensor<tf.Rank>[])[0],
(results as tf.Tensor<tf.Rank>[])[1],
model as any,
nmsDetections.selectedIndices,
nmsDetections.selectedScores,
prominentDetection.indices,
prominentDetection.values,
tensor,
readyfied,
justBoxes,
justValues,
]);
// Drawing time measuring starts
let start = performance.now();
for (const detection of chosen as any) {
ctx.strokeStyle = '#0F0';
ctx.lineWidth = 4;
ctx.globalCompositionOperation = 'destination-over';
const detectedIndex = maxIndices[detection];
const detectedClass = CLASSES[detectedIndex];
const detectedScore = scores[detection];
const dBox = boxes[detection];
// No negative values for start positions
const startY = dBox[0] > 0 ? dBox[0] * height : 0;
const startX = dBox[1] > 0 ? dBox[1] * width : 0;
const boxHeight = (dBox[2] - dBox[0]) * height;
const boxWidth = (dBox[3] - dBox[1]) * width;
ctx.strokeRect(startX, startY, boxWidth, boxHeight);
// Draw the label background.
ctx.globalCompositionOperation = 'source-over';
const textHeight = 16;
const textPad = 4;
const label = `${detectedClass} ${Math.round(detectedScore * 100)}%`;
const textWidth = (await ctx.measureText(label)).width;
ctx.fillStyle = '#0B0';
ctx.fillRect(startX, startY, textWidth + textPad, textHeight + textPad);
// Draw the text last to ensure it's on top.
ctx.fillStyle = '#000000';
ctx.fillText(label, startX, startY);
}
// Drawing time measuring ends
setDrawingTime(performance.now() - start);
};
useEffect(() => {
tf.ready().then(() => setIsTFReady(true));
}, []);
useEffect(() => {
const setupTFJS = async () => {
const model = await tf.loadGraphModel(modelPath, { fromTFHub: true });
if (perf || perfCallback) {
const perfMetrics = await perfInfo(
async () => await tensorFlowIt(model)
);
if (perf) {
setPerfProps(perfMetrics);
}
if (perfCallback) {
perfCallback(perfMetrics);
}
} else {
tensorFlowIt(model);
}
};
if (isTFReady) {
setupTFJS();
}
}, [isTFReady]);
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}
>
<View>
<Image
onLayout={event => {
setImgDimensions(event.nativeEvent.layout);
}}
source={source}
style={{ height: 300, width: 400 }}
{...props}
/>
<Canvas
ref={canvasRef}
style={{
borderColor: 'red',
borderWidth: 2,
position: 'absolute',
width: imgDimensions.width,
height: imgDimensions.height,
top: imgDimensions.y,
left: imgDimensions.x,
}}
/>
</View>
<View>
{perf && !!drawingTime && perfProps && (
<Performance {...perfProps} drawingTime={drawingTime} />
)}
</View>
</View>
);
}