diff --git a/src/Bender.tsx b/src/Bender.tsx index bb4b85b..b051709 100755 --- a/src/Bender.tsx +++ b/src/Bender.tsx @@ -1,14 +1,14 @@ -import * as React from 'react'; -import * as PropTypes from 'prop-types' -//@ts-ignore +import * as React from "react"; +import * as PropTypes from "prop-types"; +// @ts-ignore import Theme, { ThemeShape } from "./Theme"; interface BenderProps { - stylesheet: any + stylesheet: any; } interface BenderStates { - theme: any + theme: any; } /** @@ -42,11 +42,10 @@ export default class Bender extends React.Component { } componentWillReceiveProps(nextProps: BenderProps) { - if (nextProps.stylesheet !== this.props.stylesheet) { + if (nextProps.stylesheet !== this.props.stylesheet) this.setState({ theme: this.createTheme(nextProps) }); - } } createTheme(props: BenderProps) { diff --git a/src/Style.ts b/src/Style.ts index 18cf9d5..d879ef8 100644 --- a/src/Style.ts +++ b/src/Style.ts @@ -1,5 +1,9 @@ - -type FlexAlignType = "flex-start" | "flex-end" | "center" | "stretch" | "baseline"; +type FlexAlignType = + | "flex-start" + | "flex-end" + | "center" + | "stretch" + | "baseline"; /** * Flex Prop Types @@ -8,66 +12,77 @@ type FlexAlignType = "flex-start" | "flex-end" | "center" | "stretch" | "baselin * @see https://github.com/facebook/react-native/blob/master/Libraries/StyleSheet/LayoutPropTypes.js */ export interface FlexStyle { - alignContent?: "flex-start" | "flex-end" | "center" | "stretch" | "space-between" | "space-around"; - alignItems?: FlexAlignType; - alignSelf?: "auto" | FlexAlignType; - aspectRatio?: number; - borderBottomWidth?: number; - borderEndWidth?: number | string; - borderLeftWidth?: number; - borderRightWidth?: number; - borderStartWidth?: number | string; - borderTopWidth?: number; - borderWidth?: number; - bottom?: number | string; - display?: "none" | "flex"; - end?: number | string; - flex?: number; - flexBasis?: number | string; - flexDirection?: "row" | "column" | "row-reverse" | "column-reverse"; - flexGrow?: number; - flexShrink?: number; - flexWrap?: "wrap" | "nowrap" | "wrap-reverse"; - height?: number | string; - justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly"; - left?: number | string; - margin?: number | string; - marginBottom?: number | string; - marginEnd?: number | string; - marginHorizontal?: number | string; - marginLeft?: number | string; - marginRight?: number | string; - marginStart?: number | string; - marginTop?: number | string; - marginVertical?: number | string; - maxHeight?: number | string; - maxWidth?: number | string; - minHeight?: number | string; - minWidth?: number | string; - overflow?: "visible" | "hidden" | "scroll"; - padding?: number | string; - paddingBottom?: number | string; - paddingEnd?: number | string; - paddingHorizontal?: number | string; - paddingLeft?: number | string; - paddingRight?: number | string; - paddingStart?: number | string; - paddingTop?: number | string; - paddingVertical?: number | string; - position?: "absolute" | "relative"; - right?: number | string; - start?: number | string; - top?: number | string; - width?: number | string; - zIndex?: number; + alignContent?: + | "flex-start" + | "flex-end" + | "center" + | "stretch" + | "space-between" + | "space-around"; + alignItems?: FlexAlignType; + alignSelf?: "auto" | FlexAlignType; + aspectRatio?: number; + borderBottomWidth?: number; + borderEndWidth?: number | string; + borderLeftWidth?: number; + borderRightWidth?: number; + borderStartWidth?: number | string; + borderTopWidth?: number; + borderWidth?: number; + bottom?: number | string; + display?: "none" | "flex"; + end?: number | string; + flex?: number; + flexBasis?: number | string; + flexDirection?: "row" | "column" | "row-reverse" | "column-reverse"; + flexGrow?: number; + flexShrink?: number; + flexWrap?: "wrap" | "nowrap" | "wrap-reverse"; + height?: number | string; + justifyContent?: + | "flex-start" + | "flex-end" + | "center" + | "space-between" + | "space-around" + | "space-evenly"; + left?: number | string; + margin?: number | string; + marginBottom?: number | string; + marginEnd?: number | string; + marginHorizontal?: number | string; + marginLeft?: number | string; + marginRight?: number | string; + marginStart?: number | string; + marginTop?: number | string; + marginVertical?: number | string; + maxHeight?: number | string; + maxWidth?: number | string; + minHeight?: number | string; + minWidth?: number | string; + overflow?: "visible" | "hidden" | "scroll"; + padding?: number | string; + paddingBottom?: number | string; + paddingEnd?: number | string; + paddingHorizontal?: number | string; + paddingLeft?: number | string; + paddingRight?: number | string; + paddingStart?: number | string; + paddingTop?: number | string; + paddingVertical?: number | string; + position?: "absolute" | "relative"; + right?: number | string; + start?: number | string; + top?: number | string; + width?: number | string; + zIndex?: number; - /** - * @platform ios - */ - direction?: "inherit" | "ltr" | "rtl"; + /** + * @platform ios + */ + direction?: "inherit" | "ltr" | "rtl"; } - export interface ShadowStyleIOS { shadowColor?: string; shadowOffset?: { width: number; height: number }; @@ -75,7 +90,6 @@ export interface ShadowStyleIOS { shadowRadius?: number; } - interface PerpectiveTransform { perspective: number; } @@ -126,18 +140,18 @@ interface SkewYTransform { export interface TransformsStyle { transform?: ( - | PerpectiveTransform - | RotateTransform - | RotateXTransform - | RotateYTransform - | RotateZTransform - | ScaleTransform - | ScaleXTransform - | ScaleYTransform - | TranslateXTransform - | TranslateYTransform - | SkewXTransform - | SkewYTransform)[]; + | PerpectiveTransform + | RotateTransform + | RotateXTransform + | RotateYTransform + | RotateZTransform + | ScaleTransform + | ScaleXTransform + | ScaleYTransform + | TranslateXTransform + | TranslateYTransform + | SkewXTransform + | SkewYTransform)[]; transformMatrix?: Array; rotation?: number; scaleX?: number; @@ -178,18 +192,16 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle { opacity?: number; testID?: string; /** - * Sets the elevation of a view, using Android's underlying - * [elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation). - * This adds a drop shadow to the item and affects z-order for overlapping views. - * Only supported on Android 5.0+, has no effect on earlier versions. - * - * @platform android - */ + * Sets the elevation of a view, using Android's underlying + * [elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation). + * This adds a drop shadow to the item and affects z-order for overlapping views. + * Only supported on Android 5.0+, has no effect on earlier versions. + * + * @platform android + */ elevation?: number; } - - export interface TextStyleIOS extends ViewStyle { letterSpacing?: number; textDecorationColor?: string; @@ -214,11 +226,26 @@ export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle { * for most fonts. Not all fonts have a variant for each of the numeric * values, in that case the closest one is chosen. */ - fontWeight?: "normal" | "bold" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900"; + fontWeight?: + | "normal" + | "bold" + | "100" + | "200" + | "300" + | "400" + | "500" + | "600" + | "700" + | "800" + | "900"; letterSpacing?: number; lineHeight?: number; textAlign?: "auto" | "left" | "right" | "center" | "justify"; - textDecorationLine?: "none" | "underline" | "line-through" | "underline line-through"; + textDecorationLine?: + | "none" + | "underline" + | "line-through" + | "underline line-through"; textDecorationStyle?: "solid" | "double" | "dotted" | "dashed"; textDecorationColor?: string; textShadowColor?: string; @@ -227,7 +254,12 @@ export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle { testID?: string; } -export type ImageResizeMode = "cover" | "contain" | "stretch" | "repeat" | "center"; +export type ImageResizeMode = + | "cover" + | "contain" + | "stretch" + | "repeat" + | "center"; /** * Image style @@ -251,41 +283,32 @@ export interface ImageStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle { opacity?: number; } -export type ImpreciseStyle = TextStyle | ViewStyle | ImageStyle +export type ImpreciseStyle = TextStyle | ViewStyle | ImageStyle; type Falsy = undefined | null | false; interface RecursiveArray extends Array> {} export type StyleProp = T | RecursiveArray | Falsy; export function flattenStyle(style?: StyleProp) { - if (style === null || typeof style !== 'object') { - return undefined; - } + if (style === null || typeof style !== "object") return undefined; - if (!Array.isArray(style)) { - return style; - } + if (!Array.isArray(style)) return style; const result = {}; for (let i = 0, styleLength = style.length; i < styleLength; ++i) { const computedStyle = flattenStyle(style[i]); - if (computedStyle) { - for (const key in computedStyle) { - // @ts-ignore - result[key] = computedStyle[key]; - } - } + if (computedStyle) + // @ts-ignore + for (const key in computedStyle) result[key] = computedStyle[key]; } return result; } export function transformStyle(style?: ImpreciseStyle) { - if (!style) - return {}; + if (!style) return {}; - if (__DEV__) - return Object.freeze(style); + if (__DEV__) return Object.freeze(style); return style; -} \ No newline at end of file +} diff --git a/src/Theme.js b/src/Theme.js index f1dac7e..6c83493 100755 --- a/src/Theme.js +++ b/src/Theme.js @@ -38,7 +38,7 @@ let defaultTheme; */ export default class Theme { constructor(themeStyle) { - this[THEME_STYLE] = themeStyle // resolveStyle(themeStyle); + this[THEME_STYLE] = themeStyle; // resolveStyle(themeStyle); this[THEME_STYLE_CACHE] = {}; } diff --git a/src/global.d.ts b/src/global.d.ts index bf8d00d..7d9a15d 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1 +1 @@ -declare var __DEV__: boolean \ No newline at end of file +declare var __DEV__: boolean; diff --git a/src/index.ts b/src/index.ts index 63a7afd..5b0a516 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,16 +1,11 @@ -if (global) { - //@ts-ignore - global.__DEV__ = process.env.NODE_ENV === 'development'; -} else if (window) { - //@ts-ignore - window.__DEV__ = process.env.NODE_ENV === 'development'; -} +if (global) + // @ts-ignore + global.__DEV__ = process.env.NODE_ENV === "development"; +else if (window) + // @ts-ignore + window.__DEV__ = process.env.NODE_ENV === "development"; -import Bender from './Bender' -import withBenderStyles from './withBenderStyles' - -export { - Bender, - withBenderStyles -} +import Bender from "./Bender"; +import withBenderStyles from "./withBenderStyles"; +export { Bender, withBenderStyles }; diff --git a/src/mergeComponentAndThemeStyles.js b/src/mergeComponentAndThemeStyles.js index c5e958b..87dac07 100755 --- a/src/mergeComponentAndThemeStyles.js +++ b/src/mergeComponentAndThemeStyles.js @@ -1,12 +1,18 @@ -import * as _ from 'lodash'; +import * as _ from "lodash"; export default function mergeComponentAndThemeStyles( - componentStyle, themeComponentStyle, themeStyle) { + componentStyle, + themeComponentStyle, + themeStyle +) { const componentThemedStyle = _.merge({}, componentStyle, themeComponentStyle); // Picking only required root theme style, used by component. // We do not want to merge whole theme to component style. - const intersectedRootThemeStyle = _.pick(themeStyle, _.keys(componentThemedStyle)); + const intersectedRootThemeStyle = _.pick( + themeStyle, + _.keys(componentThemedStyle) + ); // Merging only common style, not all theme style with component style return _.merge({}, intersectedRootThemeStyle, componentThemedStyle); diff --git a/src/resolveComponentStyle.ts b/src/resolveComponentStyle.ts index 4e2f813..cf1c683 100755 --- a/src/resolveComponentStyle.ts +++ b/src/resolveComponentStyle.ts @@ -1,6 +1,6 @@ -import * as _ from 'lodash'; +import * as _ from "lodash"; // import { StyleProp, ViewStyle, ImageStyle, TextStyle } from 'react-native'; -import { StyleProp, ImpreciseStyle, flattenStyle } from './Style' +import { StyleProp, ImpreciseStyle, flattenStyle } from "./Style"; /** * Matches any style properties that represent component style variants. @@ -12,7 +12,7 @@ import { StyleProp, ImpreciseStyle, flattenStyle } from './Style' * @returns {boolean} True if the style property represents a component variant, false otherwise. */ const REGEX_ISSTYLE_VARIANT = /^\./; -function isStyleVariant(propertyName:string) { +function isStyleVariant(propertyName: string) { return REGEX_ISSTYLE_VARIANT.test(propertyName); } @@ -29,7 +29,7 @@ function isStyleVariant(propertyName:string) { * @returns {boolean} True if the style property represents a child style, false otherwise. */ const REGEX_IS_CHILD_STYLE = /(^[^\.].*\.)|(^[A-Z][^\s]*)|^\*$/; -function isChildStyle(propertyName:string) { +function isChildStyle(propertyName: string) { return REGEX_IS_CHILD_STYLE.test(propertyName); } @@ -44,23 +44,25 @@ function isChildStyle(propertyName:string) { * @returns {*} An object with the componentStyle, styleVariants, and childrenStyle keys. */ function splitStyle(style: any, extractDefinitions: boolean) { - return _.reduce(style, (result, value, key) => { - let styleSection: any = result.componentStyle; - if (isStyleVariant(key)) { - styleSection = result.styleVariants; - } else if (isChildStyle(key)) { - styleSection = result.childrenStyle; - } else if (extractDefinitions && typeof value === 'object') { - styleSection = result.componentDefinitions; + return _.reduce( + style, + (result, value, key) => { + let styleSection: any = result.componentStyle; + if (isStyleVariant(key)) styleSection = result.styleVariants; + else if (isChildStyle(key)) styleSection = result.childrenStyle; + else if (extractDefinitions && typeof value === "object") + styleSection = result.componentDefinitions; + + styleSection[key] = value; + return result; + }, + { + componentStyle: {}, + componentDefinitions: {}, + styleVariants: {}, + childrenStyle: {} } - styleSection[key] = value; - return result; - }, { - componentStyle: {}, - componentDefinitions: {}, - styleVariants: {}, - childrenStyle: {}, - }); + ); } /** @@ -87,33 +89,40 @@ function splitStyle(style: any, extractDefinitions: boolean) { * @returns {{componentStyle, componentDefinitions, childrenStyle}} The resolved component and children styles. */ export function resolveComponentStyle( - componentName:string, - styleNames:Array = [], + componentName: string, + styleNames: Array = [], themeStyle: any = {}, parentStyle: any = {}, elementStyle: StyleProp = {}, extractDefinitions: boolean = true -): { - componentStyle: ImpreciseStyle, - componentDefinitions: ImpreciseStyle, - childrenStyle: ImpreciseStyle +): { + componentStyle: ImpreciseStyle; + componentDefinitions: ImpreciseStyle; + childrenStyle: ImpreciseStyle; } { - const styleAllFromAncestor = parentStyle['*']; + const styleAllFromAncestor = parentStyle["*"]; const styleComponentFromAncestor = parentStyle[componentName]; - const styleAllByNameFromAncestor = _.map(styleNames, (sn) => parentStyle[`*.${sn}`]); - const styleByComponentAndNameFromAncestor = _.map(styleNames, (sn) => parentStyle[`${componentName}.${sn}`]); - const styleByProps = flattenStyle(elementStyle) + const styleAllByNameFromAncestor = _.map( + styleNames, + sn => parentStyle[`*.${sn}`] + ); + const styleByComponentAndNameFromAncestor = _.map( + styleNames, + sn => parentStyle[`${componentName}.${sn}`] + ); + const styleByProps = flattenStyle(elementStyle); // Phase 1: merge the styles in the correct order to resolve the variant styles, // the component style will be merged as well in this step, but the component // style merge results are ignored after this step. We need to perform this // step separately because the style variants may be overridden by any style, so // the purpose of this phase is to determine the final state of the variant styles. - const mergedStyle = _.merge({}, + const mergedStyle = _.merge( + {}, themeStyle, styleAllFromAncestor, styleComponentFromAncestor, - ..._.map(styleNames, (sn) => themeStyle[`.${sn}`]), + ..._.map(styleNames, sn => themeStyle[`.${sn}`]), ...styleAllByNameFromAncestor, ...styleByComponentAndNameFromAncestor, styleByProps @@ -122,21 +131,25 @@ export function resolveComponentStyle( // Phase 2: merge the component styles, this step is performed by using the // style from phase 1, so that we are sure that the final style variants are // applied to component style. - const resolvedStyle = _.merge({}, + const resolvedStyle = _.merge( + {}, mergedStyle, styleAllFromAncestor, styleComponentFromAncestor, - ..._.map(styleNames, (sn) => mergedStyle[`.${sn}`]), + ..._.map(styleNames, sn => mergedStyle[`.${sn}`]), ...styleAllByNameFromAncestor, ...styleByComponentAndNameFromAncestor, styleByProps ); - const { componentStyle, childrenStyle, componentDefinitions } = splitStyle(resolvedStyle, extractDefinitions); + const { componentStyle, childrenStyle, componentDefinitions } = splitStyle( + resolvedStyle, + extractDefinitions + ); return { componentStyle, componentDefinitions, - childrenStyle, + childrenStyle }; } diff --git a/src/resolveIncludes.js b/src/resolveIncludes.js index da58730..795dbb9 100755 --- a/src/resolveIncludes.js +++ b/src/resolveIncludes.js @@ -1,5 +1,5 @@ -import * as _ from 'lodash'; -export const INCLUDE = '@@shoutem.theme/include'; +import * as _ from "lodash"; +export const INCLUDE = "@@shoutem.theme/include"; /** * Customizer function for lodash mergeWith which handle INCLUDE symbol. @@ -12,8 +12,10 @@ function includeSymbolMergeHandler(objVal, srcVal) { let include; if (srcVal && srcVal[INCLUDE]) { - include = newObjVal && newObjVal[INCLUDE] ? - [...newObjVal[INCLUDE], ...srcVal[INCLUDE]] : srcVal[INCLUDE]; + include = + newObjVal && newObjVal[INCLUDE] + ? [...newObjVal[INCLUDE], ...srcVal[INCLUDE]] + : srcVal[INCLUDE]; } // if objVal doesn't exists create new from source @@ -72,7 +74,9 @@ export default function resolveIncludes(target, base = {}) { const baseStyle = base[styleName]; if (baseStyle) { if (baseStyle[INCLUDE]) { - throw Error(`Base style cannot have includes, unexpected include in ${styleName}.`); + throw Error( + `Base style cannot have includes, unexpected include in ${styleName}.` + ); } style = { ...baseStyle }; } @@ -81,7 +85,7 @@ export default function resolveIncludes(target, base = {}) { if (targetStyle) { style = { ...style, - ...targetStyle, + ...targetStyle }; } @@ -108,7 +112,7 @@ export default function resolveIncludes(target, base = {}) { let stylesToInclude = {}; if (styleNamesToInclude) { if (!_.isArray(styleNamesToInclude)) { - throw Error('Include should be array'); + throw Error("Include should be array"); } for (const styleName of styleNamesToInclude) { @@ -126,12 +130,19 @@ export default function resolveIncludes(target, base = {}) { } } - const resultingStyle = _.mergeWith({}, stylesToInclude, styleNode, includeSymbolMergeHandler); + const resultingStyle = _.mergeWith( + {}, + stylesToInclude, + styleNode, + includeSymbolMergeHandler + ); delete resultingStyle[INCLUDE]; for (const styleName of _.keys(resultingStyle)) { - resultingStyle[styleName] = - includeNodeStyles(resultingStyle[styleName], processingStyleNames); + resultingStyle[styleName] = includeNodeStyles( + resultingStyle[styleName], + processingStyleNames + ); } return resultingStyle; } diff --git a/src/test.ts b/src/test.ts index d7cac64..628d25a 100644 --- a/src/test.ts +++ b/src/test.ts @@ -1,7 +1,7 @@ -import ExampleComponent from './' +import ExampleComponent from "./"; -describe('ExampleComponent', () => { - it('is truthy', () => { - expect(ExampleComponent).toBeTruthy() - }) -}) +describe("ExampleComponent", () => { + it("is truthy", () => { + expect(ExampleComponent).toBeTruthy(); + }); +}); diff --git a/src/withBenderStyles.tsx b/src/withBenderStyles.tsx index 1ef1425..663d75a 100755 --- a/src/withBenderStyles.tsx +++ b/src/withBenderStyles.tsx @@ -1,28 +1,29 @@ -import * as React from 'react'; -import * as ReactIs from 'react-is'; +import * as React from "react"; +import * as ReactIs from "react-is"; -import * as PropTypes from 'prop-types' -import hoistNonReactStatics from 'hoist-non-react-statics' +import * as PropTypes from "prop-types"; +import hoistNonReactStatics from "hoist-non-react-statics"; // import hoistNonReactStatics = require('hoist-non-react-statics'); import * as _ from "lodash"; -import { StyleProp, ImpreciseStyle, transformStyle } from './Style' +import { StyleProp, ImpreciseStyle, transformStyle } from "./Style"; import { resolveComponentStyle } from "./resolveComponentStyle"; // import normalizeStyle from "./StyleNormalizer/normalizeStyle"; -// @ts-ignore +// @ts-ignore import Theme, { ThemeShape } from "./Theme"; - - /** * Formats and throws an error when connecting component style with the theme. * * @param errorMessage The error message. * @param componentDisplayName The name of the component that is being connected. */ -function throwConnectStyleError(errorMessage: string, componentDisplayName: string) { +function throwConnectStyleError( + errorMessage: string, + componentDisplayName: string +) { throw Error( `${errorMessage} - when connecting ${componentDisplayName} component to style.` ); @@ -44,10 +45,14 @@ function getTheme(context: React.ValidationMap) { type StyleNames = Array | undefined; interface MapPropsToStyleNames { + // tslint:disable-next-line (ownStyleNames: StyleNames, props: TProps): StyleNames; } -type MapPropsToStyleNamesParams = MapPropsToStyleNames | null | undefined +type MapPropsToStyleNamesParams = + | MapPropsToStyleNames + | null + | undefined; // interface StyleContext extends React.ValidationMap { // parentStyle: Object, @@ -56,24 +61,24 @@ type MapPropsToStyleNamesParams = MapPropsToStyleNames | null | // type StyleContext = React.ValidationMap; - interface ResolveStyleHandler { - (props: TProps): ImpreciseStyle + // tslint:disable-next-line + (props: TProps): ImpreciseStyle; } interface StyleContextChild { - parentStyle: Object, - resolveStyle: ResolveStyleHandler + parentStyle: object; + resolveStyle: ResolveStyleHandler; } interface BentContext { - theme: Object, - parentStyle: Object | null + theme: object; + parentStyle: object | null; } interface ConnectStyleOptions { - virtual?: Boolean, - withRef?: Boolean + virtual?: boolean; + withRef?: boolean; } // // Applies LibraryManagedAttributes (proper handling of defaultProps @@ -88,11 +93,11 @@ interface ConnectStyleOptions { // } interface WrappableProps { - style? : StyleProp - styleDefinitions?: Object + style?: StyleProp; + styleDefinitions?: object; } -type WrappableComponent = React.ComponentType +type WrappableComponent = React.ComponentType; // interface ForwardedComponent { // $$typeof$$: string @@ -121,113 +126,125 @@ type WrappableComponent = React.ComponentType * @returns {StyledComponent} The new component that will handle * the styling of the wrapped component. */ -export default function ( +export default function( componentStyleName: string, - componentStyle: Object = {}, + componentStyle: object = {}, mapPropsToStyleNames: MapPropsToStyleNamesParams, - options:ConnectStyleOptions = {} + options: ConnectStyleOptions = {} ): any { - - return function bendComponent(WrappedComponent: WrappableComponent) { if (!ReactIs.isValidElementType(WrappedComponent)) - throw new Error( - "WrappedComponent is not a valid React component!" - ); + throw new Error("WrappedComponent is not a valid React component!"); - const wrappedComponentName = WrappedComponent.displayName - || WrappedComponent.name - || componentStyleName + const wrappedComponentName = + WrappedComponent.displayName || + WrappedComponent.name || + componentStyleName; - if (!_.isPlainObject(componentStyle)) { + if (!_.isPlainObject(componentStyle)) throwConnectStyleError( "Component style must be plain object", wrappedComponentName ); - } - if (!_.isString(componentStyleName)) { + if (!_.isString(componentStyleName)) throwConnectStyleError( "Component Style Name must be string", wrappedComponentName ); - } - function isStateful():boolean { - //@ts-ignore - return (WrappedComponent.prototype !== undefined && WrappedComponent.prototype.render !== undefined) || (WrappedComponent.render !== undefined) + function isStateful(): boolean { + return ( + (WrappedComponent.prototype !== undefined && + WrappedComponent.prototype.render !== undefined) || + // @ts-ignore + WrappedComponent.render !== undefined + ); } interface BenderProps { // Element style that overrides any other style of the component - style: StyleProp, + style: StyleProp; // The style variant names to apply to this component, // multiple variants may be separated with a space character - styleName: string, + styleName: string; // Virtual elements will propagate the parent // style to their children, i.e., the children // will behave as they are placed directly below // the parent of a virtual element. - virtual: boolean, + virtual: boolean; // Extracts @style-def definitions as a separate style definitions // that will be passed into wrapped component as `styleDefinitons` prop. - extractDefinitions: boolean, + extractDefinitions: boolean; } - + interface BenderStates { - styleNames?: Array, + styleNames?: Array; styles: { - component: Object, - definitions?: Object - }, + component: object; + definitions?: object; + }; // addedProps: Object, - childrenStyle: Object + childrenStyle: object; } - class BenderComponent extends React.Component - implements - React.ChildContextProvider> - { + implements React.ChildContextProvider> { static contextTypes: React.ValidationMap = { theme: ThemeShape, // The style inherited from the parent parentStyle: PropTypes.object }; - - static childContextTypes: React.ValidationMap> = { + + static childContextTypes: React.ValidationMap< + StyleContextChild + > = { // Provide the parent style to child components parentStyle: PropTypes.object.isRequired, resolveStyle: PropTypes.func.isRequired }; - + static defaultProps = { virtual: options.virtual, extractDefinitions: true }; - + static displayName = `withBenderStyles(${wrappedComponentName})`; static WrappedComponent: WrappableComponent = WrappedComponent; - - wrappedRef:any = null - constructor(props: BenderProps, context: React.ValidationMap) { + wrappedRef: any = null; + + constructor( + props: BenderProps, + context: React.ValidationMap + ) { super(props, context); const styleNames = this.resolveStyleNames(props); - const { componentStyle, componentDefinitions, childrenStyle } = this.resolveStyle(context, props.style, styleNames, props.extractDefinitions); - + const { + componentStyle, + componentDefinitions, + childrenStyle + } = this.resolveStyle( + context, + props.style, + styleNames, + props.extractDefinitions + ); + this.state = { styles: { - component: props.extractDefinitions ? transformStyle(componentStyle) : componentStyle, + component: props.extractDefinitions + ? transformStyle(componentStyle) + : componentStyle, definitions: componentDefinitions }, - childrenStyle: childrenStyle, + childrenStyle, styleNames }; this.setWrappedRef = this.setWrappedRef.bind(this); } - + getChildContext(): StyleContextChild { return { // if virtual is set then propagate the connected parent style @@ -238,12 +255,19 @@ export default function ( resolveStyle: this.resolveConnectedComponentStyle }; } - - componentWillReceiveProps(nextProps: BenderProps, nextContext: React.ValidationMap) { + + componentWillReceiveProps( + nextProps: BenderProps, + nextContext: React.ValidationMap + ) { const styleNames = this.resolveStyleNames(nextProps); - + if (this.shouldRebuildStyle(nextProps, nextContext, styleNames)) { - const { componentStyle, childrenStyle, componentDefinitions } = this.resolveStyle( + const { + componentStyle, + childrenStyle, + componentDefinitions + } = this.resolveStyle( nextContext, nextProps.style, styleNames, @@ -252,7 +276,9 @@ export default function ( this.setState({ styles: { - component: nextProps.extractDefinitions ? transformStyle(componentStyle) : componentStyle, + component: nextProps.extractDefinitions + ? transformStyle(componentStyle) + : componentStyle, definitions: componentDefinitions }, childrenStyle, @@ -260,29 +286,25 @@ export default function ( }); } } - - setNativeProps(nativeProps:Object) { + + setNativeProps(nativeProps: object) { if (!this.wrappedRef) { - console.warn('setNativeProps can\'nt be used on stateless components'); + // tslint:disable-next-line + console.warn("setNativeProps can'nt be used on stateless components"); return; } - if (this.wrappedRef.setNativeProps) { + if (this.wrappedRef.setNativeProps) this.wrappedRef.setNativeProps(nativeProps); - } } - + setWrappedRef(component: any) { - if (!component) - return; + if (!component) return; - if (component.wrappedRef) { - this.wrappedRef = component.wrappedRef; - } else { - this.wrappedRef = component; - } + if (component.wrappedRef) this.wrappedRef = component.wrappedRef; + else this.wrappedRef = component; } - + hasStyleNameChanged(nextProps: BenderProps, styleNames: StyleNames) { return ( mapPropsToStyleNames && @@ -292,8 +314,12 @@ export default function ( !_.isEqual(this.state.styleNames, styleNames) ); } - - shouldRebuildStyle(nextProps: BenderProps, nextContext: React.ValidationMap, styleNames: StyleNames) { + + shouldRebuildStyle( + nextProps: BenderProps, + nextContext: React.ValidationMap, + styleNames: StyleNames + ) { return ( nextProps.style !== this.props.style || nextProps.styleName !== this.props.styleName || @@ -302,43 +328,43 @@ export default function ( this.hasStyleNameChanged(nextProps, styleNames) ); } - + resolveStyleNames(props: BenderProps): StyleNames { const { styleName } = props; const styleNames = styleName ? styleName.split(/\s/g) : []; - - if (!mapPropsToStyleNames) { - return styleNames; - } - + + if (!mapPropsToStyleNames) return styleNames; + // We only want to keep the unique style names return _.uniq(mapPropsToStyleNames(styleNames, props)); } - - resolveStyle(context: React.ValidationMap, - styleProp: StyleProp, + + resolveStyle( + context: React.ValidationMap, + styleProp: StyleProp, styleNames: StyleNames, - extractDefinitions: boolean) { + extractDefinitions: boolean + ) { const { parentStyle } = context; - + const theme = getTheme(context); - //@ts-ignore + // @ts-ignore const themeStyle = theme.createComponentStyle( componentStyleName, componentStyle ); - + return resolveComponentStyle( componentStyleName, styleNames, themeStyle, parentStyle, styleProp, - extractDefinitions, + extractDefinitions ); } - + /** * A helper function provided to child components that enables * them to resolve their style for any set of prop values. @@ -347,10 +373,13 @@ export default function ( * @returns {*} The resolved component style. */ resolveConnectedComponentStyle(props: BenderProps): ImpreciseStyle { - debugger const styleNames = this.resolveStyleNames(props); - return this.resolveStyle(this.context, props.style, styleNames, props.extractDefinitions) - .componentStyle; + return this.resolveStyle( + this.context, + props.style, + styleNames, + props.extractDefinitions + ).componentStyle; } // flattenStylesOverProps(props: BenderProps, style: Object): any { @@ -360,10 +389,12 @@ export default function ( // return style; // } - + render() { const { styles } = this.state; - const addedProps = isStateful() ? { ref: this.setWrappedRef } : undefined + const addedProps = isStateful() + ? { ref: this.setWrappedRef } + : undefined; return (