react-native-ui-lib
Version: 
[](https://travis-ci.org/wix/react-native-ui-lib) [](https://www.npmjs.com/package/react-native-ui-lib) [![NPM Down
199 lines (178 loc) • 5.23 kB
JavaScript
import _ from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import {StyleSheet} from 'react-native';
import {BlurView} from 'react-native-blur';
import {Constants} from '../../helpers';
import {Colors, BorderRadiuses} from '../../style';
import {BaseComponent} from '../../commons';
import View from '../view';
import TouchableOpacity from '../touchableOpacity';
import CardSection from './CardSection';
import CardItem from './CardItem';
import CardImage from './CardImage';
const DEFAULT_BORDER_RADIUS = BorderRadiuses.br40;
/**
 * @description: Card component
 * @extends: TouchableOpacity
 * @extendsnotes: (Touchable when passing onPress)
 * @extendslink: docs/TouchableOpacity
 * @modifiers: margin, padding
 * @gif: https://media.giphy.com/media/l0HU9SKWmv0VTOYMM/giphy.gif
 * @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/CardsScreen.js
 */
class Card extends BaseComponent {
  static displayName = 'Card';
  static propTypes = {
    /**
     * card custom width
     */
    width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    /**
     * card custom height
     */
    height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    /**
     * should inner card flow direction be horizontal
     */
    row: PropTypes.bool,
    /**
     * card border radius (will be passed to inner Card.Image component)
     */
    borderRadius: PropTypes.number,
    /**
     * action for when pressing the card
     */
    onPress: PropTypes.func,
    /**
     * whether the card should have shadow or not
     */
    enableShadow: PropTypes.bool,
    /**
     * elevation value (Android only)
     */
    elevation: PropTypes.number,
    /**
     * enable blur effect (iOS only)
     */
    enableBlur: PropTypes.bool,
    /**
     * blur option for blur effect according to react-native-blur lib (make sure enableBlur is on)
     */
    blurOptions: PropTypes.object,
    /**
     * Additional styles for the top container
     */
    containerStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array])
  };
  static defaultProps = {
    enableShadow: true
  };
  generateStyles() {
    this.styles = createStyles(this.getThemeProps());
  }
  getBlurOptions() {
    const {blurOptions} = this.getThemeProps();
    return {
      blurType: 'light',
      blurAmount: 5,
      ...blurOptions
    };
  }
  // todo: add unit test
  calcImagePosition(childIndex) {
    const {row, children} = this.props;
    const childrenCount = React.Children.count(children);
    const position = [];
    if (childIndex === 0) {
      position.push(row ? 'left' : 'top');
    }
    if (childIndex === childrenCount - 1) {
      position.push(row ? 'right' : 'bottom');
    }
    return position;
  }
  get elevationStyle() {
    const {elevation, enableShadow} = this.getThemeProps();
    if (enableShadow) {
      return {elevation: elevation || 2};
    }
  }
  get shadowStyle() {
    const {enableShadow} = this.getThemeProps();
    if (enableShadow) {
      return this.styles.containerShadow;
    }
  }
  get blurBgStyle() {
    const {enableBlur} = this.getThemeProps();
    if (Constants.isIOS && enableBlur) {
      return {backgroundColor: Colors.rgba(Colors.white, 0.85)};
    } else {
      return {backgroundColor: Colors.white};
    }
  }
  renderChildren() {
    const {borderRadius} = this.getThemeProps();
    const children = React.Children.map(this.props.children, (child, index) => {
      if (_.get(child, 'type') === CardImage) {
        const position = this.calcImagePosition(index);
        return React.cloneElement(child, {/* key: index, */ position, borderRadius});
      }
      return child;
    });
    return children;
  }
  render() {
    const {onPress, style, containerStyle, enableShadow, borderRadius, enableBlur, ...others} = this.getThemeProps();
    const blurOptions = this.getBlurOptions();
    const Container = onPress ? TouchableOpacity : View;
    const brRadius = borderRadius || DEFAULT_BORDER_RADIUS;
    return (
      <Container
        style={[
          this.styles.container,
          {borderRadius: brRadius},
          this.elevationStyle,
          this.shadowStyle,
          this.blurBgStyle,
          containerStyle,
          style
        ]}
        onPress={onPress}
        delayPressIn={10}
        activeOpacity={0.6}
        {...others}
        ref={this.setRef}
      >
        {Constants.isIOS && enableBlur && <BlurView style={[this.styles.blurView, {borderRadius: brRadius}]} {...blurOptions} />}
        {this.renderChildren()}
      </Container>
    );
  }
}
function createStyles({width, height, borderRadius = DEFAULT_BORDER_RADIUS}) {
  return StyleSheet.create({
    container: {
      width,
      height,
      overflow: 'visible',
      borderRadius
    },
    containerShadow: {
      // sh30 bottom
      shadowColor: Colors.dark40,
      shadowOpacity: 0.25,
      shadowRadius: 12,
      shadowOffset: {height: 5, width: 0}
    },
    blurView: {
      ...StyleSheet.absoluteFillObject,
      borderRadius
    }
  });
}
Card.Section = CardSection;
Card.Item = CardItem;
Card.Image = CardImage;
export default Card;