UNPKG

@platform/css

Version:

Helpers for working with inline CSS.

269 lines (268 loc) 8.24 kB
import { jss, R, valueUtil } from '../common'; import { toEdges } from './util'; export * from './util'; export const MEDIA_QUERY_RETINA = `@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)`; export const image = (image1x, image2x, options = { width: 10, height: 10 }) => { if (!image1x) { throw new Error('Must have at least a 1x image.'); } const { width, height } = options; const result = { width, height, backgroundImage: `url(${image1x})`, backgroundSize: `${width}px ${height}px`, backgroundRepeat: 'no-repeat', }; if (image2x) { result[MEDIA_QUERY_RETINA] = { backgroundImage: `url(${image2x})`, }; } return result; }; const mergeAndReplace = (key, value, target) => { Object.assign(target, value); delete target[key]; return target; }; const formatImage = (key, value, target) => { let [image1x, image2x, width, height] = value; if (typeof image2x === 'number') { height = width; width = image2x; image2x = undefined; } const options = { width: width, height: height, }; const style = image(image1x, image2x, options); mergeAndReplace(key, style, target); }; export const toPositionEdges = (key, value = undefined) => { const edges = toEdges(value); if (R.isEmpty(edges)) { return undefined; } const { left, top, right, bottom } = edges; if (top === undefined && right === undefined && bottom === undefined && left === undefined) { return undefined; } return { position: key.toLowerCase(), top, right, bottom, left, }; }; export const formatPositionEdges = (key, target) => { const styles = toPositionEdges(key, target[key]); mergeAndReplace(key, styles, target); }; const formatAbsoluteCenter = (key, value, target) => { if (value === true) { value = 'xy'; } if (value === false || value === undefined || value === null) { return; } const styles = { position: 'absolute', left: target.left, top: target.top, transform: '', }; const stringValue = value .toString() .trim() .toLowerCase(); if (stringValue.includes('x')) { styles.left = '50%'; } if (stringValue.includes('y')) { styles.top = '50%'; } let transform; switch (value) { case 'yx': case 'xy': transform = 'translate(-50%, -50%)'; break; case 'x': transform = 'translateX(-50%)'; break; case 'y': transform = 'translateY(-50%)'; break; default: throw new Error(`AbsoluteCenter value '${value}' not supported.`); } styles.transform = `${target.transform || ''} ${transform}`.trim(); mergeAndReplace(key, styles, target); }; function formatSpacingPlane(plane, prefix, key, value, target) { const styles = {}; const edges = toEdges(value); if (edges && plane.includes('x')) { styles[`${prefix}Left`] = edges.left; styles[`${prefix}Right`] = edges.right; } if (edges && plane.includes('y')) { styles[`${prefix}Top`] = edges.top; styles[`${prefix}Bottom`] = edges.bottom; } mergeAndReplace(key, styles, target); } function formatScroll(key, value, target) { if (value === true) { const styles = { overflowX: 'hidden', overflowY: 'scroll', WebkitOverflowScrolling: 'touch', }; mergeAndReplace(key, styles, target); } if (value === false) { const styles = { overflow: 'hidden', }; mergeAndReplace(key, styles, target); } } const AlignMap = { center: 'center', left: 'flex-start', top: 'flex-start', start: 'flex-start', right: 'flex-end', bottom: 'flex-end', end: 'flex-end', full: 'stretch', stretch: 'stretch', baseline: 'baseline', }; function convertCrossAlignToFlex(token) { return AlignMap[token] || undefined; } const MainAlignMap = { center: 'center', left: 'flex-start', top: 'flex-start', start: 'flex-start', right: 'flex-end', bottom: 'flex-end', end: 'flex-end', spaceBetween: 'space-between', spaceAround: 'space-around', spaceEvenly: 'space-evenly', }; function convertMainAlignToFlex(token) { return MainAlignMap[token] || undefined; } function formatFlexPosition(key, value, target) { let direction; let mainAlignment; let crossAlignment; const tokens = value.split('-').map(token => token.trim()); tokens.map(token => { const tokenIsOneOf = (options) => options.includes(token); if (direction == null && tokenIsOneOf(['horizontal', 'vertical'])) { direction = token === 'vertical' ? 'column' : 'row'; return; } if (tokenIsOneOf(['center', 'start', 'end', 'left', 'right', 'top', 'bottom', 'full', 'baseline'])) { if (crossAlignment == null) { if (direction == null && tokenIsOneOf(['left', 'right'])) { direction = 'column'; } if (direction == null && tokenIsOneOf(['top', 'bottom'])) { direction = 'row'; } crossAlignment = convertCrossAlignToFlex(token); return; } mainAlignment = convertMainAlignToFlex(token); return; } if (tokenIsOneOf(['spaceAround', 'spaceBetween', 'spaceEvenly'])) { mainAlignment = convertMainAlignToFlex(token); return; } }); const styles = { display: 'flex', flexDirection: direction, alignItems: crossAlignment, justifyContent: mainAlignment, }; mergeAndReplace(key, styles, target); } export const transform = (style = {}) => { if (style == null) { return {}; } if (style === false) { return {}; } if (typeof style !== 'object') { return style; } Object.keys(style).forEach(key => { const value = style[key]; if (value === false || value === null || value === undefined) { delete style[key]; } else if (valueUtil.isPlainObject(value)) { style[key] = transform(value); } else { switch (key) { case 'Image': formatImage(key, value, style); break; case 'Absolute': formatPositionEdges(key, style); break; case 'Fixed': formatPositionEdges(key, style); break; case 'AbsoluteCenter': formatAbsoluteCenter(key, value, style); break; case 'Margin': formatSpacingPlane('xy', 'margin', key, value, style); break; case 'MarginX': formatSpacingPlane('x', 'margin', key, value, style); break; case 'MarginY': formatSpacingPlane('y', 'margin', key, value, style); break; case 'Padding': formatSpacingPlane('xy', 'padding', key, value, style); break; case 'PaddingX': formatSpacingPlane('x', 'padding', key, value, style); break; case 'PaddingY': formatSpacingPlane('y', 'padding', key, value, style); break; case 'Flex': formatFlexPosition(key, value, style); break; case 'Scroll': formatScroll(key, value, style); break; default: } } }); return style; }; const formatCss = (...styles) => { return jss.css(...styles.map(transform)); }; formatCss.image = image; export const format = formatCss;