UNPKG

vcc-ui

Version:

A React library for building user interfaces at Volvo Cars

150 lines (146 loc) 5.05 kB
import { assignStyle } from 'css-in-js-utils'; import { createRenderer } from 'fela'; import enforceLonghandsEnhancer from 'fela-enforce-longhands'; import embedded from 'fela-plugin-embedded'; import extend from 'fela-plugin-extend'; import falllbackValue from 'fela-plugin-fallback-value'; import hoverMedia from 'fela-plugin-hover-media'; import namedKeys from 'fela-plugin-named-keys'; import prefixer from 'fela-plugin-prefixer'; import responsiveValue from 'fela-plugin-responsive-value'; import rtl from 'fela-plugin-rtl'; import themeValue from 'fela-plugin-theme-value'; import unit from 'fela-plugin-unit'; import sortClassnames from 'fela-sort-classnames'; import sortMediaQueryMobileFirst from 'fela-sort-media-query-mobile-first'; import { mapValueToMediaQuery } from 'fela-tools'; // whitelisting all the props that support responsive array values export const responsiveProps = { alignContent: true, alignItems: true, alignSelf: true, aspectRatio: true, columnGap: true, display: true, flex: true, flexBasis: true, flexDirection: true, flexGrow: true, flexShrink: true, flexWrap: true, gap: true, height: true, justifyContent: true, margin: true, marginBottom: true, marginLeft: true, marginRight: true, marginTop: true, maxHeight: true, maxWidth: true, minHeight: true, minWidth: true, order: true, padding: true, paddingBottom: true, paddingLeft: true, paddingRight: true, paddingTop: true, rowGap: true, textAlign: true, width: true }; const getResponsiveMediaQueries = (values, props) => { const { fromM, fromL, fromXL } = props.theme.breakpoints; const mediaQueryMap = { 2: [fromM], 3: [fromM, fromL], 4: [fromM, fromL, fromXL] }; return mediaQueryMap[values.length]; }; export function styleRenderer() { let { isRtl, enforceLonghands = true, wrapHoverWithMediaHover = false, renderFonts = true, ...rest } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; const options = rest || {}; // eslint-disable-next-line testing-library/render-result-naming-convention const renderer = createRenderer({ ...options, enhancers: [sortClassnames(), sortMediaQueryMobileFirst(), ...(enforceLonghands ? [enforceLonghandsEnhancer()] : []), ...(options.enhancers || [])], plugins: [responsiveObjectValue(responsiveProps), extend(), embedded(), responsiveValue(getResponsiveMediaQueries, responsiveProps), namedKeys(props => props && props.theme && props.theme.breakpoints || {}), renderFonts && themeFontsPlugin, rtl(isRtl ? 'rtl' : 'ltr'), themeValue({ color: theme => theme.color, backgroundColor: theme => theme.color, borderColor: theme => theme.color, stroke: theme => theme.color, fill: theme => theme.color, '--icon-color': theme => theme.color, '--icon-color-secondary': theme => theme.color }), ...(options.plugins || []), unit(), falllbackValue(), prefixer(), wrapHoverWithMediaHover && hoverMedia()].filter(Boolean) }); return renderer; } // TODO: move to fela repo as an official plugin function themeFontsPlugin(style, type, renderer, props) { const fonts = props.theme && props.theme.fonts || []; const fontsPath = props.theme && props.theme.fontsPath || ''; for (const property in style) { const value = style[property]; // TODO: maybe we wanna cache already rendered fonts // but no high prio as Fela does that as well if (typeof value === 'string' && property === 'fontFamily') { // check each alternative font value const fontValues = value.split(','); const usedFonts = fonts.filter(font => fontValues.indexOf(font.fontFamily) !== -1); if (usedFonts.length > 0) { usedFonts.forEach(_ref => { let { fontFamily, src, ...fontProps } = _ref; return renderer.renderFont(fontFamily, src.map( // allow absolute files with http prefix file => (file.indexOf('http') === -1 ? fontsPath : '') + file), fontProps); }); } } else if (typeof value === 'object' && !Array.isArray(value)) { themeFontsPlugin(value, type, renderer, props); } } return style; } // TODO: move to fela repo as an official plugin function resolveResponsiveObjectValues(style, properties) { for (const property in style) { if (properties[property]) { const value = style[property]; if (typeof value === 'object' && !Array.isArray(value)) { const { default: defaultValue, ...mediaValues } = value; assignStyle(style, { [property]: defaultValue }, { extend: [mapValueToMediaQuery(mediaValues, value => ({ [property]: value }))] }); } } } return style; } function responsiveObjectValue() { let properties = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return style => resolveResponsiveObjectValues(style, properties); }