Skip to content

Commit

Permalink
Merge 02d1f34 into 37274c4
Browse files Browse the repository at this point in the history
  • Loading branch information
artyorsh authored Dec 13, 2018
2 parents 37274c4 + 02d1f34 commit f1c7a73
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 84 deletions.
4 changes: 4 additions & 0 deletions src/framework/theme/component/mapping/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ export interface ThemeMappingType {
variants: any;
}

export interface VariantType {
state: any;
}

export type TokenType = any;
12 changes: 11 additions & 1 deletion src/framework/theme/component/style/styleConsumer.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface Props {
variant: string;
theme?: ThemeType;
themedStyle?: StyleType;
requestStateStyle?: (state?: string) => StyleType;
}

export const StyledComponent = <T extends React.Component, P extends object>(Component: React.ComponentClass<P>) => {
Expand All @@ -36,12 +37,21 @@ export const StyledComponent = <T extends React.Component, P extends object>(Com

getComponentName = (): string => Component.displayName || Component.name;

createStyle = (mapping: ThemeMappingType,
theme: ThemeType,
variant: string,
state?: string): StyleType | undefined => {

return createStyle(theme, mapping, variant, state);
};

createCustomProps = (props: ConsumerProps, variant: string): Props => {
const mapping = getComponentThemeMapping(this.getComponentName(), props.mapping);
return {
variant: variant,
theme: props.theme,
themedStyle: mapping && props.theme && createStyle(props.theme, mapping, variant),
themedStyle: this.createStyle(mapping, props.theme, variant),
requestStateStyle: (state: string) => this.createStyle(mapping, props.theme, variant, state),
};
};

Expand Down
68 changes: 31 additions & 37 deletions src/framework/theme/service/mappingUtil.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { ThemeMappingType, TokenType } from '../component';
import {
ThemeMappingType,
VariantType,
TokenType,
} from '../component';

export const VARIANT_DEFAULT = 'default';

Expand All @@ -19,37 +23,49 @@ export function getComponentThemeMapping(component: string, mapping: any): Theme
* @return TokenType if presents in tokens, undefined otherwise
*/
export function getThemeMappingToken(token: string, tokens: TokenType): TokenType | undefined {
if (tokens[token] !== undefined) {
const value = {};
value[token] = tokens[token];
return value;
} else {
if (tokens[token] === undefined) {
return undefined;
}
const value = {};
value[token] = tokens[token];

return value;
}

/**
* @param variant: string - variant name. Default is 'default'
* @param mapping: ThemeMappingType - component mapping configuration
* @param state: string - variant state name. Default is `undefined`
*
* @return variant if presents in mapping, undefined otherwise
*/
export function getComponentVariant(variant: string, mapping: ThemeMappingType): any | undefined {
return mapping.variants[variant];
export function getComponentVariant(variant: string,
mapping: ThemeMappingType,
state?: string): any | undefined {

const componentVariant: VariantType = mapping.variants[variant];
if (componentVariant === undefined) {
return undefined;
}
const { state: variantStates, ...variantParameters } = componentVariant;

return state === undefined ? variantParameters : variantStates[state];
}

/**
* @param parameter: string - parameter name.
* @param variant: string - variant name. Default is 'default'
* @param variant: string - variant name.
* @param mapping: ThemeMappingType - component mapping configuration
* @param state: string - variant state name
*
* @return parameterMapping if presents in variant, undefined otherwise
*/
export function getParameterMapping(parameter: string,
variant: string,
mapping: ThemeMappingType): any | undefined {
mapping: ThemeMappingType,
state?: string): any | undefined {

const componentVariant = getComponentVariant(variant, mapping);
const componentVariant = getComponentVariant(variant, mapping, state);
return componentVariant && componentVariant[parameter];
}

Expand All @@ -58,38 +74,16 @@ export function getParameterMapping(parameter: string,
* @param variant: string - variant name.
* @param mapping: ThemeMappingType - component mapping configuration
* @param tokens: TokenType - theme tokens
* @param state: string - variant state name
*
* @return theme token if presents in variant, undefined otherwise
*/
export function getParameterValue(parameter: string,
variant: string,
mapping: ThemeMappingType,
tokens: TokenType): any | undefined {
tokens: TokenType,
state?: string): any | undefined {

const parameterMapping = getParameterMapping(parameter, variant, mapping);
const parameterMapping = getParameterMapping(parameter, variant, mapping, state);
return parameterMapping && getThemeMappingToken(parameterMapping, tokens);
}

/**
* @param tokens: TokenType - theme mapping tokens array
* @param mapping: ThemeMappingType - component mapping configuration
* @param variant: string - variant name. Default is 'default'
*
* @return TokenType specific for component's variant if presents in variant, undefined otherwise
*/
export function getVariantTokens(tokens: TokenType,
mapping: ThemeMappingType,
variant: string = VARIANT_DEFAULT): TokenType | undefined {

const componentVariant = getComponentVariant(variant, mapping);
if (componentVariant === undefined) {
return undefined;
}
const assignParameter = (origin: TokenType, parameter: string) => {
return {
...origin,
...getParameterValue(parameter, variant, mapping, tokens),
};
};
return Object.keys(componentVariant).reduce(assignParameter, {});
}
33 changes: 21 additions & 12 deletions src/framework/theme/service/themeUtil.service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import {
getComponentVariant,
VARIANT_DEFAULT,
} from './mappingUtil.service';
import {
ThemeMappingType,
ThemeType,
StyleType,
} from '../component';
import { StyleType, ThemeMappingType, ThemeType } from '../component';

const variantSeparator = ' ';

Expand All @@ -15,7 +11,8 @@ const variantSeparator = ' ';
*
* @param theme: ThemeType - theme object
* @param mapping: ThemeMappingType - component theme mapping configuration
* @param variant: string | string[] - variant name. Default is 'default'.
* @param variant: string | string[] - variant name.
* @param state: string - variant state. Default is `undefined`.
* Supported argument formats:
* - 'dark'
* - 'dark success'
Expand All @@ -25,15 +22,20 @@ const variantSeparator = ' ';
*/
export function createStyle(theme: ThemeType,
mapping: ThemeMappingType,
variant: string[] | string = [VARIANT_DEFAULT]): StyleType {
variant: string[] | string = [VARIANT_DEFAULT],
state?: string): StyleType {

const variants: string[] = Array.isArray(variant) ? variant : variant.split(variantSeparator);

const mapVariant = (v: string) => createStyleFromVariant(theme, mapping, v);
const mapStateVariant = (v: string) => state && createStyleFromVariant(theme, mapping, v, state);
const mergeStyles = (origin: StyleType, next: StyleType) => ({ ...origin, ...next });

const defaultStyle = createStyleFromVariant(theme, mapping, VARIANT_DEFAULT);
return variants.map(mapVariant).reduce(mergeStyles, defaultStyle);
const defaultStyle = mapVariant(VARIANT_DEFAULT);
const variantStyle = variants.map(mapVariant).reduce(mergeStyles, defaultStyle);
const variantStateStyle = variants.map(mapStateVariant).reduce(mergeStyles, {});

return mergeStyles(variantStyle, variantStateStyle);
}

/**
Expand All @@ -46,9 +48,16 @@ export function getThemeValue(name: string, theme: ThemeType): any | undefined {
return theme[name];
}

function createStyleFromVariant(theme: ThemeType, mapping: ThemeMappingType, variant: string): StyleType {
const componentVariant = getComponentVariant(variant, mapping);
const assignParameter = (style: any, parameter: any) => {
export function createStyleFromVariant(theme: ThemeType,
mapping: ThemeMappingType,
variant: string,
state?: string): StyleType {

const componentVariant = getComponentVariant(variant, mapping, state);
if (componentVariant === undefined) {
return undefined;
}
const assignParameter = (style: StyleType, parameter: any) => {
style[parameter] = getThemeValue(componentVariant[parameter], theme);
return style;
};
Expand Down
21 changes: 21 additions & 0 deletions src/framework/theme/tests/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const values = {
textDefault: '#000000',
textDark: '#ffffff',
textSuccess: '#00E676',
textSuccessActive: '#81C784',
};

export const mappings = {
Expand All @@ -14,17 +15,36 @@ export const mappings = {
'backgroundColor',
'textColor',
],
states: [
'active',
],
variants: {
default: {
backgroundColor: 'backgroundColorTestDefault',
textColor: 'textColorTestDefault',
state: {
active: {
backgroundColor: 'backgroundColorTestDark',
textColor: 'textColorTestDark',
},
},
},
dark: {
backgroundColor: 'backgroundColorTestDark',
textColor: 'textColorTestDark',
state: {
active: {
backgroundColor: 'backgroundColorTestDefault',
},
},
},
success: {
textColor: 'textColorTestSuccess',
state: {
active: {
textColor: 'textColorTestSuccessActive',
},
},
},
},
},
Expand All @@ -36,6 +56,7 @@ export const theme: ThemeType = {
textColorTestDefault: values.textDefault,
textColorTestDark: values.textDark,
textColorTestSuccess: values.textSuccess,
textColorTestSuccessActive: values.textSuccessActive,
};

export const themeInverse: ThemeType = {
Expand Down
53 changes: 38 additions & 15 deletions src/framework/theme/tests/mapping.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
getComponentVariant,
getParameterValue,
getThemeMappingToken,
getVariantTokens,
} from '../service';

describe('@mapping: service methods checks', () => {
Expand All @@ -21,21 +20,56 @@ describe('@mapping: service methods checks', () => {

it('finds variant properly', async () => {
const componentVariant = getComponentVariant('default', config.mappings.Test);
const componentStateVariant = getComponentVariant('default', config.mappings.Test, 'active');
const undefinedVariant = getComponentVariant('undefined', config.mappings.Test);
const undefinedStateVariant = getComponentVariant('default', config.mappings.Test, 'undefined');

expect(componentVariant).not.toBeNull();
expect(componentVariant).not.toBeUndefined();
expect(JSON.stringify(componentVariant)).toEqual(JSON.stringify(config.mappings.Test.variants.default));
expect(componentStateVariant).not.toBeNull();
expect(componentStateVariant).not.toBeUndefined();
expect(undefinedVariant).toBeUndefined();
expect(undefinedStateVariant).toBeUndefined();

const { state: variantState, ...variant } = config.mappings.Test.variants.default;
expect(JSON.stringify(componentVariant)).toEqual(JSON.stringify(variant));
expect(JSON.stringify(componentStateVariant)).toEqual(JSON.stringify(variantState.active));
});

it('finds parameter value properly', async () => {
const parameterValue = getParameterValue('backgroundColor', 'default', config.mappings.Test, config.theme);
const undefinedValue = getParameterValue('undefined', 'default', config.mappings.Test, config.theme);
const parameterValue = getParameterValue(
'backgroundColor',
'default',
config.mappings.Test,
config.theme,
);
const stateParameterValue = getParameterValue(
'backgroundColor',
'default',
config.mappings.Test,
config.theme,
'active',
);
const undefinedValue = getParameterValue(
'undefined',
'default',
config.mappings.Test,
config.theme,
);
const undefinedStateValue = getParameterValue(
'backgroundColor',
'default',
config.mappings.Test,
config.theme,
'undefined',
);

expect(parameterValue).not.toBeNull();
expect(parameterValue).not.toBeUndefined();
expect(stateParameterValue).not.toBeNull();
expect(stateParameterValue).not.toBeUndefined();
expect(undefinedValue).toBeUndefined();
expect(undefinedStateValue).toBeUndefined();
});

it('finds token properly', async () => {
Expand All @@ -48,15 +82,4 @@ describe('@mapping: service methods checks', () => {
expect(undefinedToken).toBeUndefined();
});

it('finds default mapping tokens properly', async () => {
const variantTokens = getVariantTokens(config.theme, config.mappings.Test);
const undefinedTokens = getVariantTokens(config.theme, config.mappings.Test, 'undefined');

expect(variantTokens.backgroundColorTestDefault).not.toBeNull();
expect(variantTokens.backgroundColorTestDefault).not.toBeUndefined();
expect(variantTokens.textColorTestDefault).not.toBeNull();
expect(variantTokens.textColorTestDefault).not.toBeUndefined();
expect(undefinedTokens).toBeUndefined();
});

});
26 changes: 26 additions & 0 deletions src/framework/theme/tests/style.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ describe('@style: style consumer checks', () => {
expect(styledComponent.props.theme).not.toBeUndefined();
expect(styledComponent.props.themedStyle).not.toBeNull();
expect(styledComponent.props.themedStyle).not.toBeUndefined();
expect(styledComponent.props.requestStateStyle).not.toBeNull();
expect(styledComponent.props.requestStateStyle).not.toBeUndefined();
});

it('default variant styled properly', async () => {
Expand Down Expand Up @@ -125,6 +127,30 @@ describe('@style: style consumer checks', () => {
expect(styledComponent.props.themedStyle.textColor).toEqual(config.values.textSuccess);
});

it('style request works properly', async () => {
const StyleConsumer = StyledComponent(Test);

const component = render(
<StyleProvider mapping={config.mappings} theme={config.theme}>
<StyleConsumer variant='dark success'/>
</StyleProvider>,
);

const styledComponent = component.getByTestId(styleConsumerTestId);
const stateStyle = styledComponent.props.requestStateStyle('active');
const undefinedStateStyle = styledComponent.props.requestStateStyle('undefined');

expect(stateStyle).not.toBeNull();
expect(stateStyle).not.toBeUndefined();
expect(stateStyle.backgroundColor).toEqual(config.values.backgroundDefault);
expect(stateStyle.textColor).toEqual(config.values.textSuccessActive);

expect(undefinedStateStyle).not.toBeNull();
expect(undefinedStateStyle).not.toBeUndefined();
expect(undefinedStateStyle.backgroundColor).toEqual(config.values.backgroundDark);
expect(undefinedStateStyle.textColor).toEqual(config.values.textSuccess);
});

it('static methods are copied over', async () => {
// @ts-ignore: test-case
Test.staticMethod = function() {};
Expand Down
Loading

0 comments on commit f1c7a73

Please sign in to comment.