From 9eb16ef3a7637d18c64aa1d73aff897d85192f21 Mon Sep 17 00:00:00 2001 From: Sebastian Dovenor Date: Thu, 12 Jul 2018 17:26:28 -0400 Subject: [PATCH] feat(fscomponents): refactor ProductItem component to be option based BREAKING CHANGE: Individual ProductItemVertical, etc... components no longer exist BREAKING CHANGE: Button props have been updated to match theme Add theme to fscomponents --- .../fscomponents/src/components/Button.tsx | 135 +++------- .../__stories__/MultiCarousel.story.tsx | 4 +- .../components/ProductItem/ProductItem.tsx | 254 ++++++++++++++++++ .../ProductItem/ProductItemHorizontalGrid.tsx | 120 --------- .../ProductItem/ProductItemHorizontalList.tsx | 121 --------- .../ProductItem/ProductItemProps.tsx | 75 ------ .../ProductItem/ProductItemVerticalAction.tsx | 159 ----------- .../ProductItemVerticalBottomSwatches.tsx | 128 --------- .../ProductItemVerticalFavorite.tsx | 137 ---------- .../ProductItem/ProductItemVerticalList.tsx | 101 ------- .../ProductItemVerticalReviews.tsx | 117 -------- .../ProductItemVerticalTopSwatches.tsx | 125 --------- .../components/ProductItemBrand.tsx | 12 +- .../components/ProductItemButton.tsx | 53 ++++ .../components/ProductItemFavoriteButton.tsx | 2 +- .../components/ProductItemImage.tsx | 53 +++- .../components/ProductItemPrice.tsx | 22 +- .../components/ProductItemPromos.tsx | 13 +- .../components/ProductItemReviews.tsx | 20 +- .../components/ProductItemSwatches.tsx | 11 +- .../components/ProductItemTitle.tsx | 15 +- .../components/ProductItemVariant.tsx | 2 +- .../ProductItem/components/index.tsx | 1 + .../src/components/ProductItem/index.ts | 11 +- .../src/components/ReviewIndicator.tsx | 8 +- .../__stories__/ProductItem.story.tsx | 127 ++++----- .../components/__stories__/Shelf.story.tsx | 4 +- packages/fscomponents/src/styles/Button.ts | 22 +- .../src/styles/ReviewIndicator.ts | 19 +- packages/fscomponents/src/styles/Swatches.ts | 6 +- packages/fscomponents/src/styles/variables.ts | 88 ++++++ .../src/styles/weights.android.ts | 32 +++ packages/fscomponents/src/styles/weights.ts | 25 ++ .../src/components/ProductIndexGrid.tsx | 4 +- .../pirateship/src/components/PSButton.tsx | 80 +----- .../src/components/PSProductCarousel.tsx | 7 +- .../src/components/PSProductIndex.tsx | 7 +- .../src/components/PSRequireSignIn.tsx | 5 +- .../src/components/PSSignInForm.tsx | 8 +- packages/pirateship/src/screens/Cart.tsx | 22 +- .../pirateship/src/screens/ChangePassword.tsx | 1 - .../pirateship/src/screens/EditAddress.tsx | 1 - .../pirateship/src/screens/EditPersonal.tsx | 1 - .../pirateship/src/screens/ForgotPassword.tsx | 2 - packages/pirateship/src/screens/Search.tsx | 6 +- packages/pirateship/src/screens/Shop.tsx | 1 - packages/pirateship/src/screens/SignUp.tsx | 1 - .../src/screens/TrackOrderLanding.tsx | 3 +- packages/pirateship/src/styles/variables.ts | 14 +- 49 files changed, 720 insertions(+), 1465 deletions(-) create mode 100644 packages/fscomponents/src/components/ProductItem/ProductItem.tsx delete mode 100644 packages/fscomponents/src/components/ProductItem/ProductItemHorizontalGrid.tsx delete mode 100644 packages/fscomponents/src/components/ProductItem/ProductItemHorizontalList.tsx delete mode 100644 packages/fscomponents/src/components/ProductItem/ProductItemProps.tsx delete mode 100644 packages/fscomponents/src/components/ProductItem/ProductItemVerticalAction.tsx delete mode 100644 packages/fscomponents/src/components/ProductItem/ProductItemVerticalBottomSwatches.tsx delete mode 100644 packages/fscomponents/src/components/ProductItem/ProductItemVerticalFavorite.tsx delete mode 100644 packages/fscomponents/src/components/ProductItem/ProductItemVerticalList.tsx delete mode 100644 packages/fscomponents/src/components/ProductItem/ProductItemVerticalReviews.tsx delete mode 100644 packages/fscomponents/src/components/ProductItem/ProductItemVerticalTopSwatches.tsx create mode 100644 packages/fscomponents/src/components/ProductItem/components/ProductItemButton.tsx create mode 100644 packages/fscomponents/src/styles/variables.ts create mode 100644 packages/fscomponents/src/styles/weights.android.ts create mode 100644 packages/fscomponents/src/styles/weights.ts diff --git a/packages/fscomponents/src/components/Button.tsx b/packages/fscomponents/src/components/Button.tsx index 4f65be1c4e..2dee8118e9 100644 --- a/packages/fscomponents/src/components/Button.tsx +++ b/packages/fscomponents/src/components/Button.tsx @@ -13,29 +13,16 @@ import { } from 'react-native'; import { darken } from '../lib/color'; +import { border, palette } from '../styles/variables'; import { style as S, stylesSize, - stylesTextColor, stylesTextSize } from '../styles/Button'; import { Loading } from './Loading'; const DEFAULT_TINT_PERC = 15; -export interface StylesColor { - primary: string; - secondary: string; - success: string; - info: string; - warning: string; - alert: string; - dark: string; - light: string; - disabled: string; - link: string; -} - export interface ButtonProps extends Pick { title: string; accessibilityLabel?: string; @@ -44,20 +31,16 @@ export interface ButtonProps extends Pick void; titleStyle?: StyleProp; underlayColor?: string; - variables?: { - color: any; - }; icon?: ImageURISource; iconStyle?: StyleProp; viewStyle?: StyleProp; - // color - primary?: boolean; - secondary?: boolean; - success?: boolean; - warning?: boolean; - alert?: boolean; - dark?: boolean; + // style + palette?: typeof palette; + color?: keyof typeof palette; + size?: keyof typeof stylesSize; + + // types light?: boolean; link?: boolean; @@ -65,34 +48,18 @@ export interface ButtonProps extends Pick { - stylesColor: StylesColor; - - constructor(props: ButtonProps) { - super(props); - - const { variables = { color: {} } } = props; +export interface ButtonState { + palette: any; +} - // TODO: stylesColor should be state and this should run inside getDerivedStateFromProps - this.stylesColor = { - alert: variables.color.alert || '#f9373e', - dark: variables.color.dark || '#555555', - disabled: variables.color.disabled || '#eeeeee', - info: variables.color.info || '#3adb76', - light: variables.color.light || '#eeeeee', - link: 'transparent', - primary: variables.color.primary || '#4078c0', - secondary: variables.color.secondary || '#707070', - success: variables.color.success || '#3adb76', - warning: variables.color.warning || '#ffae00' - }; - } +export class Button extends PureComponent { + state: ButtonState = { + palette: this.props.palette || palette + }; render(): any { const { @@ -103,11 +70,14 @@ export class Button extends PureComponent { underlayColor, full, accessibilityLabel, - hitSlop + hitSlop, + size = 'medium', + color = 'primary', + light, + link } = this.props; - const color = this.getColor(this.props); - const size = this.getSize(this.props); + const { palette } = this.state; return ( { onPress={onPress} onLongPress={onLongPress} underlayColor={ - underlayColor || darken(this.stylesColor[color], DEFAULT_TINT_PERC) + underlayColor || darken(palette[color], DEFAULT_TINT_PERC) } hitSlop={hitSlop} style={[ S.container, - { backgroundColor: this.stylesColor[color] }, + { + backgroundColor: light || link ? 'transparent' : palette[color], + borderColor: light ? palette[color] : undefined, + borderWidth: light ? border.width : 0 + }, stylesSize[size], full && S.full, style @@ -140,11 +114,15 @@ export class Button extends PureComponent { iconStyle, title, titleStyle, - viewStyle + viewStyle, + size = 'medium', + color = 'primary', + light, + link } = this.props; - const color = this.getColor(this.props); - const size = this.getSize(this.props); + const { palette } = this.state; + const onColor = 'on' + color.charAt(0).toUpperCase() + color.slice(1); if (loading) { return ; @@ -155,12 +133,7 @@ export class Button extends PureComponent { { ); } } - - private getColor = (props: ButtonProps) => { - if (props.primary) { - return 'primary'; - } - if (props.secondary) { - return 'secondary'; - } - if (props.success) { - return 'success'; - } - if (props.warning) { - return 'warning'; - } - if (props.alert) { - return 'alert'; - } - if (props.dark) { - return 'dark'; - } - if (props.light) { - return 'light'; - } - if (props.disabled) { - return 'disabled'; - } - if (props.link) { - return 'link'; - } - return 'primary'; - } - - private getSize = (props: ButtonProps) => { - if (props.small) { - return 'small'; - } - return 'large'; - } } diff --git a/packages/fscomponents/src/components/MultiCarousel/__stories__/MultiCarousel.story.tsx b/packages/fscomponents/src/components/MultiCarousel/__stories__/MultiCarousel.story.tsx index d25282f7bb..ebbdaf3d33 100644 --- a/packages/fscomponents/src/components/MultiCarousel/__stories__/MultiCarousel.story.tsx +++ b/packages/fscomponents/src/components/MultiCarousel/__stories__/MultiCarousel.story.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; // tslint:disable-line:no-implicit-dependencies import { action } from '@storybook/addon-actions'; // tslint:disable-line:no-implicit-dependencies import { MultiCarousel } from '../MultiCarousel'; -import { ProductItemVerticalList } from '../../ProductItem/ProductItemVerticalList'; +import { ProductItem } from '../../ProductItem'; import Decimal from 'decimal.js'; const productItems = [...Array(10)].map((a, i) => ({ @@ -13,7 +13,7 @@ const productItems = [...Array(10)].map((a, i) => ({ const renderItem = (item: any) => { return ( - ; + contentStyle?: StyleProp; + titleStyle?: StyleProp; + brandStyle?: StyleProp; + imageStyle?: StyleProp; + imageContainerStyle?: StyleProp; + onPress: () => void; + priceStyle?: StyleProp; + originalPriceStyle?: StyleProp; + salePriceStyle?: StyleProp; + promoContainerStyle?: StyleProp; + promoStyle?: StyleProp; + variantText?: string; + variantTextStyle?: StyleProp; + reviewStyle?: StyleProp; + reviewCountStyle?: StyleProp; + reviewIndicatorProps?: ReviewIndicatorProps; + extraElement?: JSX.Element; + swatchItems?: SwatchItemType[]; + swatchStyle?: StyleProp; + swatchesProps?: SwatchesProps; + + /** + * @deprecated you probably want FSCommerce's "promotions" + */ + promos?: string[]; + /** + * @deprecated you probably want FSCommerce's "images" + */ + image?: ImageURISource; + /** + * @deprecated you probably want FSCommerce's "reviews" + */ + reviewValue?: number; + /** + * @deprecated you probably want FSCommerce's "reviews" + */ + reviewCount?: number; + showReviewCount?: boolean; + + // button + buttonText?: string; + buttonStyle?: StyleProp; + buttonTextStyle?: StyleProp; + buttonProps?: Partial; + onButtonPress?: () => void; + renderButton?: () => React.ReactNode; + + // fav button + onFavButtonPress?: () => void; + favButtonImage?: ImageURISource; + renderFavButton?: () => React.ReactNode; + + // custom render + renderPrice?: () => React.ReactNode; + renderPromos?: () => React.ReactNode; + renderTitle?: () => React.ReactNode; + renderVariantText?: () => React.ReactNode; + renderBrand?: () => React.ReactNode; + renderImage?: () => React.ReactNode; + renderReviews?: () => React.ReactNode; + renderSwatches?: () => React.ReactNode; + + // hide components + hidePrice?: boolean; + hidePromos?: boolean; + hideTitle?: boolean; + hideVariantText?: boolean; + hideBrand?: boolean; + hideImage?: boolean; + hideReviews?: boolean; + hideSwatches?: boolean; + hideButton?: boolean; + + // orientation + orientation?: 'vertical' | 'horizontal'; +} + +export class ProductItem extends Component { + + // tslint:disable cyclomatic-complexity + render(): JSX.Element { + const { + style, + contentStyle, + onPress, + extraElement = null, + title, + images, + imageStyle, + imageContainerStyle, + renderImage, + image, // deprecated + variantText, + variantTextStyle, + renderVariantText, + brand, + brandStyle, + renderBrand, + titleStyle, + renderTitle, + review, + reviewStyle, + reviewCountStyle, + reviewIndicatorProps, + renderReviews, + reviewValue, // deprecated + reviewCount, // deprecated + price, + originalPrice, + priceStyle, + originalPriceStyle, + salePriceStyle, + renderPrice, + promotions, + promoStyle, + promoContainerStyle, + renderPromos, + promos, // deprecated + swatchItems, + swatchStyle, + swatchesProps, + renderSwatches, + hidePrice, + hidePromos, + hideTitle, + hideVariantText, + hideBrand, + hideImage, + hideReviews, + hideSwatches, + hideButton, + buttonText, + buttonStyle, + buttonTextStyle, + buttonProps, + onButtonPress, + renderButton, + orientation = 'vertical' + } = this.props; + + const isHorizontal = (orientation === 'horizontal'); + + return ( + + + + + {!hideImage && } + {!hideVariantText && } + + + {!hideSwatches && } + {!hideBrand && } + {!hideTitle && } + {!hidePrice && } + {!hideReviews && } + {!hidePromos && } + {extraElement} + + + + {!hideButton && } + + + + ); + } +} diff --git a/packages/fscomponents/src/components/ProductItem/ProductItemHorizontalGrid.tsx b/packages/fscomponents/src/components/ProductItem/ProductItemHorizontalGrid.tsx deleted file mode 100644 index 8d21eeb04d..0000000000 --- a/packages/fscomponents/src/components/ProductItem/ProductItemHorizontalGrid.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import React, { Component } from 'react'; -import { - TouchableWithoutFeedback, - View -} from 'react-native'; -import { ProductItemProps } from './ProductItemProps'; -import { style as S } from '../../styles/ProductItem'; -import { - ProductItemBrand, - ProductItemImage, - ProductItemPrice, - ProductItemPromos, - ProductItemReviews, - ProductItemTitle, - ProductItemVariant -} from './components'; - -export class ProductItemHorizontalGrid extends Component { - render(): JSX.Element { - const { - style, - contentStyle, - onPress, - extraElement = null, - title, - images, - imageStyle, - imageContainerStyle, - renderImage, - image, // deprecated - variantText, - variantTextStyle, - renderVariantText, - brand, - brandStyle, - renderBrand, - titleStyle, - renderTitle, - review, - reviewStyle, - reviewCountStyle, - reviewIndicatorProps, - renderReviews, - reviewValue, // deprecated - reviewCount, // deprecated - price, - originalPrice, - priceStyle, - originalPriceStyle, - salePriceStyle, - renderPrice, - promotions, - promoStyle, - promoContainerStyle, - renderPromos, - promos // deprecated - } = this.props; - - return ( - - - - - - - - - - - - - {extraElement} - - - - ); - } -} diff --git a/packages/fscomponents/src/components/ProductItem/ProductItemHorizontalList.tsx b/packages/fscomponents/src/components/ProductItem/ProductItemHorizontalList.tsx deleted file mode 100644 index c7f0fe8d34..0000000000 --- a/packages/fscomponents/src/components/ProductItem/ProductItemHorizontalList.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import React, { Component } from 'react'; -import { - TouchableWithoutFeedback, - View -} from 'react-native'; - -import { ProductItemProps } from './ProductItemProps'; -import { style as S } from '../../styles/ProductItem'; -import { - ProductItemBrand, - ProductItemImage, - ProductItemPrice, - ProductItemPromos, - ProductItemReviews, - ProductItemTitle, - ProductItemVariant -} from './components'; - -export class ProductItemHorizontalList extends Component { - render(): JSX.Element { - const { - style, - contentStyle, - onPress, - extraElement = null, - title, - images, - imageStyle, - imageContainerStyle, - renderImage, - image, // deprecated - variantText, - variantTextStyle, - renderVariantText, - brand, - brandStyle, - renderBrand, - titleStyle, - renderTitle, - review, - reviewStyle, - reviewCountStyle, - reviewIndicatorProps, - renderReviews, - reviewValue, // deprecated - reviewCount, // deprecated - price, - originalPrice, - priceStyle, - originalPriceStyle, - salePriceStyle, - renderPrice, - promotions, - promoStyle, - promoContainerStyle, - renderPromos, - promos // deprecated - } = this.props; - - return ( - - - - - - - - - - - - - {extraElement} - - - - ); - } -} diff --git a/packages/fscomponents/src/components/ProductItem/ProductItemProps.tsx b/packages/fscomponents/src/components/ProductItem/ProductItemProps.tsx deleted file mode 100644 index c0e9510fe4..0000000000 --- a/packages/fscomponents/src/components/ProductItem/ProductItemProps.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { - ImageStyle, - ImageURISource, - StyleProp, - TextStyle, - ViewStyle -} from 'react-native'; -import { CommerceTypes } from '@brandingbrand/fscommerce'; -import { ButtonProps } from '../Button'; -import { ReviewIndicatorProps } from '../ReviewIndicator'; -import { SwatchesProps, SwatchItemType } from '../Swatches'; - -export interface ProductItemProps extends CommerceTypes.Product { - style?: StyleProp; - contentStyle?: StyleProp; - titleStyle?: StyleProp; - brandStyle?: StyleProp; - imageStyle?: StyleProp; - imageContainerStyle?: StyleProp; - onPress: () => void; - priceStyle?: StyleProp; - originalPriceStyle?: StyleProp; - salePriceStyle?: StyleProp; - promoContainerStyle?: StyleProp; - promoStyle?: StyleProp; - variantText?: string; - variantTextStyle?: StyleProp; - reviewStyle?: StyleProp; - reviewCountStyle?: StyleProp; - reviewIndicatorProps?: ReviewIndicatorProps; - extraElement?: JSX.Element; - swatchItems?: SwatchItemType[]; - swatchStyle?: StyleProp; - swatchesProps?: SwatchesProps; - - /** - * @deprecated you probably want FSCommerce's "promotions" - */ - promos?: string[]; - /** - * @deprecated you probably want FSCommerce's "images" - */ - image?: ImageURISource; - /** - * @deprecated you probably want FSCommerce's "reviews" - */ - reviewValue?: number; - /** - * @deprecated you probably want FSCommerce's "reviews" - */ - reviewCount?: number; - - // button - buttonText?: string; - buttonStyle?: StyleProp; - buttonTextStyle?: StyleProp; - buttonProps?: ButtonProps; - onButtonPress?: () => void; - renderButton?: () => React.ReactNode; - - // fav button - onFavButtonPress?: () => void; - favButtonImage?: ImageURISource; - renderFavButton?: () => React.ReactNode; - - // custom render - renderPrice?: () => React.ReactNode; - renderPromos?: () => React.ReactNode; - renderTitle?: () => React.ReactNode; - renderVariantText?: () => React.ReactNode; - renderBrand?: () => React.ReactNode; - renderImage?: () => React.ReactNode; - renderReviews?: () => React.ReactNode; - renderSwatches?: () => React.ReactNode; -} diff --git a/packages/fscomponents/src/components/ProductItem/ProductItemVerticalAction.tsx b/packages/fscomponents/src/components/ProductItem/ProductItemVerticalAction.tsx deleted file mode 100644 index 928af7cbfd..0000000000 --- a/packages/fscomponents/src/components/ProductItem/ProductItemVerticalAction.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import React, { Component } from 'react'; -import { - TouchableWithoutFeedback, - View -} from 'react-native'; -import { Button } from '../Button'; -import { ProductItemProps } from './ProductItemProps'; -import { - ProductItemBrand, - ProductItemImage, - ProductItemPrice, - ProductItemPromos, - ProductItemReviews, - ProductItemSwatches, - ProductItemTitle, - ProductItemVariant -} from './components'; - -export class ProductItemVerticalAction extends Component { - renderButton = () => { - const { - buttonText, - buttonStyle, - buttonTextStyle, - buttonProps, - onButtonPress, - renderButton - } = this.props; - - if (renderButton) { - return renderButton(); - } - - if (!buttonText || !onButtonPress) { - return null; - } - - return ( -