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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
  );
}