UNPKG

hypertoxin

Version:

A themeable ReactNative component library for developing native apps

333 lines (311 loc) 11.6 kB
/** * Copyright 2016-present Tuan Le. * * Licensed under the MIT License. * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://opensource.org/licenses/mit-license.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *------------------------------------------------------------------------ * * @module CoverImage * @description - Cover image component. * * @author Tuan Le (tuan.t.lei@gmail.com) * * @flow */ 'use strict'; // eslint-disable-line import React from 'react'; import ReactNative from 'react-native'; // eslint-disable-line import PropTypes from 'prop-types'; import { DefaultTheme, DefaultThemeContext } from '../../themes/default-theme'; const { Dimensions, ImageBackground } = ReactNative; const DEVICE_WIDTH = Dimensions.get(`window`).width; const DEVICE_HEIGHT = Dimensions.get(`window`).height; const DEFAULT_DROP_SHADOW_STYLE = { shadowColor: `#000000`, shadowRadius: 1, shadowOpacity: 0.25, shadowOffset: { width: 1, height: 2 } }; const DEFAULT_COVER_IMAGE_STYLE = { flexDirection: `column`, justifyContent: `center`, alignItems: `center`, maxWidth: DEVICE_WIDTH, maxHeight: DEVICE_HEIGHT }; const CoverImage = (props) => { const { exclusions, shade, width, height, corner, margin, resizeMode, dropShadowed, source, defaultSource, style, children } = props; let contentChildren = null; if (React.Children.count(children) > 0) { contentChildren = React.Children.toArray(React.Children.map(children, (child) => { if (child !== null) { const inheritedProps = Array.isArray(exclusions) ? Object.entries({ shade }).filter(([ propName, prop // eslint-disable-line ]) => exclusions.every((exclusion) => propName !== exclusion)).reduce((_inheritedProps, [ propName, prop ]) => { _inheritedProps[propName] = prop; return _inheritedProps; }, {}) : { shade }; return React.cloneElement(child, inheritedProps); } return null; })); } return ( <DefaultThemeContext.Consumer> { (context = { Theme: DefaultTheme }) => { const { Theme } = context; const nullMargin = { margin: null, marginTop: null, marginBottom: null, marginLeft: null, marginRight: null, marginHorizontal: null, marginVertical: null }; const nullBorderRadius = { borderTopLeftRadius: null, borderTopRightRadius: null, borderBottomLeftRadius: null, borderBottomRightRadius: null }; let dropShadow; let themedBorderRadius; let themedCorner; let themedMargin; if (typeof corner === `string`) { if (corner === `themed`) { if (typeof Theme.image.cover.corner === `string` && Theme.image.corner.cover.hasOwnProperty(Theme.image.cover.corner)) { themedCorner = Theme.image.corner.cover[Theme.image.cover.corner]; } else { themedCorner = Theme.image.cover.corner; } } else if (Theme.image.corner.cover.hasOwnProperty(corner)) { themedCorner = Theme.image.corner.cover[corner]; } else { themedCorner = 0; } } else { themedCorner = corner; } if (typeof themedCorner === `number`) { themedBorderRadius = { borderRadius: themedCorner }; } else if (typeof themedCorner === `object`) { themedBorderRadius = Object.entries(themedCorner).reduce((_themedBorderRadius, [ key, value ]) => { let _borderRadius = nullBorderRadius; _borderRadius[`border${key.charAt(0).toUpperCase()}${key.slice(1)}Radius`] = value; _themedBorderRadius = { ..._themedBorderRadius, ..._borderRadius }; return _themedBorderRadius; }, nullBorderRadius); } if (typeof margin === `string`) { if (margin === `themed`) { if (typeof Theme.image.cover.margin === `string` && Theme.image.margin.cover.hasOwnProperty(Theme.image.cover.margin)) { themedMargin = Theme.image.margin.cover[Theme.image.cover.margin]; } else { themedMargin = Theme.image.cover.margin; } } else if (Theme.image.margin.cover.hasOwnProperty(margin)) { themedMargin = Theme.image.margin.cover[margin]; } else { themedMargin = 0; } } else { themedMargin = margin; } if (typeof themedMargin === `number`) { themedMargin = { ...nullMargin, margin: themedMargin }; } else if (typeof themedMargin === `object`) { themedMargin = Object.entries(themedMargin).reduce((_themedMargin, [ key, value ]) => { let _margin = nullMargin; _margin[`margin${key.charAt(0).toUpperCase()}${key.slice(1)}`] = value; _themedMargin = { ..._themedMargin, ..._margin }; return _themedMargin; }, nullMargin); } if ((typeof dropShadowed === `boolean` && dropShadowed) || (dropShadowed === `themed` && Theme.image.cover.dropShadowed)) { dropShadow = DEFAULT_DROP_SHADOW_STYLE; } else { dropShadow = { ...DEFAULT_DROP_SHADOW_STYLE, shadowRadius: 0, shadowOpacity: 0, shadowOffset: { width: 0, height: 0 } }; } return ( <ImageBackground style = {{ ...DEFAULT_COVER_IMAGE_STYLE, ...dropShadow, width, height, ...themedMargin, ...themedBorderRadius, ...(typeof style === `object` ? style : {}) }} imageStyle = {{ ...themedBorderRadius }} source = { typeof source === `string` ? { uri: source, cache: `only-if-cached` } : source } defaultSource = { typeof source === `string` ? { uri: defaultSource } : defaultSource } resizeMode = { resizeMode } > { contentChildren } </ImageBackground> ); } } </DefaultThemeContext.Consumer> ); }; const ImageURISourcePropType = PropTypes.shape({ uri: PropTypes.string, bundle: PropTypes.string, method: PropTypes.string, headers: PropTypes.objectOf(PropTypes.string), body: PropTypes.string, cache: PropTypes.oneOf([ `default`, `reload`, `force-cache`, `only-if-cached` ]), width: PropTypes.number, height: PropTypes.number, scale: PropTypes.number }); CoverImage.propTypes = { exclusions: PropTypes.arrayOf(PropTypes.string), room: PropTypes.oneOf([ `none`, `content-left`, `content-middle`, `content-right`, `content-bottom`, `content-top`, `media`, `activity-indicator` ]), shade: PropTypes.oneOf([ `themed`, `light`, `dark` ]), width: PropTypes.number, height: PropTypes.number, corner: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.shape({ topLeft: PropTypes.number, topRight: PropTypes.number, bottomLeft: PropTypes.number, bottomRight: PropTypes.number }) ]), margin: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.shape({ top: PropTypes.number, bottom: PropTypes.number, left: PropTypes.number, right: PropTypes.number, horizontal: PropTypes.number, vertical: PropTypes.number }) ]), resizeMode: PropTypes.oneOf([ `cover`, `contain`, `stretch`, `repeat`, `center` ]), dropShadowed: PropTypes.oneOfType([ PropTypes.bool, PropTypes.string ]), source: PropTypes.oneOfType([ () => null, PropTypes.string, PropTypes.number, ImageURISourcePropType, PropTypes.arrayOf(ImageURISourcePropType) ]), defaultSource: PropTypes.oneOfType([ () => null, PropTypes.string, PropTypes.number, ImageURISourcePropType, PropTypes.arrayOf(ImageURISourcePropType) ]) }; CoverImage.defaultProps = { exclusions: [ `` ], room: `none`, shade: `themed`, width: 0, height: 0, corner: `themed`, margin: `themed`, resizeMode: `contain`, dropShadowed: `themed`, source: null, defaultSource: null }; export default CoverImage;