You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					98 lines
				
				2.6 KiB
			
		
		
			
		
	
	
					98 lines
				
				2.6 KiB
			| 
											3 years ago
										 | // @flow | ||
|  | import between from './between' | ||
|  | import PolishedError from '../internalHelpers/_errors' | ||
|  | 
 | ||
|  | import type { FluidRangeConfiguration } from '../types/fluidRangeConfiguration' | ||
|  | import type { Styles } from '../types/style' | ||
|  | 
 | ||
|  | /** | ||
|  |  * Returns a set of media queries that resizes a property (or set of properties) between a provided fromSize and toSize. Accepts optional minScreen (defaults to '320px') and maxScreen (defaults to '1200px') to constrain the interpolation. | ||
|  |  * | ||
|  |  * @example | ||
|  |  * // Styles as object usage | ||
|  |  * const styles = { | ||
|  |  *   ...fluidRange( | ||
|  |  *    { | ||
|  |  *        prop: 'padding', | ||
|  |  *        fromSize: '20px', | ||
|  |  *        toSize: '100px', | ||
|  |  *      }, | ||
|  |  *      '400px', | ||
|  |  *      '1000px', | ||
|  |  *    ) | ||
|  |  * } | ||
|  |  * | ||
|  |  * // styled-components usage | ||
|  |  * const div = styled.div` | ||
|  |  *   ${fluidRange( | ||
|  |  *      { | ||
|  |  *        prop: 'padding', | ||
|  |  *        fromSize: '20px', | ||
|  |  *        toSize: '100px', | ||
|  |  *      }, | ||
|  |  *      '400px', | ||
|  |  *      '1000px', | ||
|  |  *    )} | ||
|  |  * ` | ||
|  |  * | ||
|  |  * // CSS as JS Output | ||
|  |  * | ||
|  |  * div: { | ||
|  |  *   "@media (min-width: 1000px)": Object { | ||
|  |  *     "padding": "100px", | ||
|  |  *   }, | ||
|  |  *   "@media (min-width: 400px)": Object { | ||
|  |  *     "padding": "calc(-33.33333333333334px + 13.333333333333334vw)", | ||
|  |  *   }, | ||
|  |  *   "padding": "20px", | ||
|  |  * } | ||
|  |  */ | ||
|  | export default function fluidRange( | ||
|  |   cssProp: Array<FluidRangeConfiguration> | FluidRangeConfiguration, | ||
|  |   minScreen?: string = '320px', | ||
|  |   maxScreen?: string = '1200px', | ||
|  | ): Styles { | ||
|  |   if ((!Array.isArray(cssProp) && typeof cssProp !== 'object') || cssProp === null) { | ||
|  |     throw new PolishedError(49) | ||
|  |   } | ||
|  | 
 | ||
|  |   if (Array.isArray(cssProp)) { | ||
|  |     const mediaQueries = {} | ||
|  |     const fallbacks = {} | ||
|  |     for (const obj of cssProp) { | ||
|  |       if (!obj.prop || !obj.fromSize || !obj.toSize) { | ||
|  |         throw new PolishedError(50) | ||
|  |       } | ||
|  | 
 | ||
|  |       fallbacks[obj.prop] = obj.fromSize | ||
|  |       mediaQueries[`@media (min-width: ${minScreen})`] = { | ||
|  |         ...mediaQueries[`@media (min-width: ${minScreen})`], | ||
|  |         [obj.prop]: between(obj.fromSize, obj.toSize, minScreen, maxScreen), | ||
|  |       } | ||
|  |       mediaQueries[`@media (min-width: ${maxScreen})`] = { | ||
|  |         ...mediaQueries[`@media (min-width: ${maxScreen})`], | ||
|  |         [obj.prop]: obj.toSize, | ||
|  |       } | ||
|  |     } | ||
|  | 
 | ||
|  |     return { | ||
|  |       ...fallbacks, | ||
|  |       ...mediaQueries, | ||
|  |     } | ||
|  |   } else { | ||
|  |     if (!cssProp.prop || !cssProp.fromSize || !cssProp.toSize) { | ||
|  |       throw new PolishedError(51) | ||
|  |     } | ||
|  | 
 | ||
|  |     return { | ||
|  |       [cssProp.prop]: cssProp.fromSize, | ||
|  |       [`@media (min-width: ${minScreen})`]: { | ||
|  |         [cssProp.prop]: between(cssProp.fromSize, cssProp.toSize, minScreen, maxScreen), | ||
|  |       }, | ||
|  |       [`@media (min-width: ${maxScreen})`]: { | ||
|  |         [cssProp.prop]: cssProp.toSize, | ||
|  |       }, | ||
|  |     } | ||
|  |   } | ||
|  | } |