fluidRange.js.flow 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // @flow
  2. import between from './between'
  3. import PolishedError from '../internalHelpers/_errors'
  4. import type { FluidRangeConfiguration } from '../types/fluidRangeConfiguration'
  5. import type { Styles } from '../types/style'
  6. /**
  7. * 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.
  8. *
  9. * @example
  10. * // Styles as object usage
  11. * const styles = {
  12. * ...fluidRange(
  13. * {
  14. * prop: 'padding',
  15. * fromSize: '20px',
  16. * toSize: '100px',
  17. * },
  18. * '400px',
  19. * '1000px',
  20. * )
  21. * }
  22. *
  23. * // styled-components usage
  24. * const div = styled.div`
  25. * ${fluidRange(
  26. * {
  27. * prop: 'padding',
  28. * fromSize: '20px',
  29. * toSize: '100px',
  30. * },
  31. * '400px',
  32. * '1000px',
  33. * )}
  34. * `
  35. *
  36. * // CSS as JS Output
  37. *
  38. * div: {
  39. * "@media (min-width: 1000px)": Object {
  40. * "padding": "100px",
  41. * },
  42. * "@media (min-width: 400px)": Object {
  43. * "padding": "calc(-33.33333333333334px + 13.333333333333334vw)",
  44. * },
  45. * "padding": "20px",
  46. * }
  47. */
  48. export default function fluidRange(
  49. cssProp: Array<FluidRangeConfiguration> | FluidRangeConfiguration,
  50. minScreen?: string = '320px',
  51. maxScreen?: string = '1200px',
  52. ): Styles {
  53. if ((!Array.isArray(cssProp) && typeof cssProp !== 'object') || cssProp === null) {
  54. throw new PolishedError(49)
  55. }
  56. if (Array.isArray(cssProp)) {
  57. const mediaQueries = {}
  58. const fallbacks = {}
  59. for (const obj of cssProp) {
  60. if (!obj.prop || !obj.fromSize || !obj.toSize) {
  61. throw new PolishedError(50)
  62. }
  63. fallbacks[obj.prop] = obj.fromSize
  64. mediaQueries[`@media (min-width: ${minScreen})`] = {
  65. ...mediaQueries[`@media (min-width: ${minScreen})`],
  66. [obj.prop]: between(obj.fromSize, obj.toSize, minScreen, maxScreen),
  67. }
  68. mediaQueries[`@media (min-width: ${maxScreen})`] = {
  69. ...mediaQueries[`@media (min-width: ${maxScreen})`],
  70. [obj.prop]: obj.toSize,
  71. }
  72. }
  73. return {
  74. ...fallbacks,
  75. ...mediaQueries,
  76. }
  77. } else {
  78. if (!cssProp.prop || !cssProp.fromSize || !cssProp.toSize) {
  79. throw new PolishedError(51)
  80. }
  81. return {
  82. [cssProp.prop]: cssProp.fromSize,
  83. [`@media (min-width: ${minScreen})`]: {
  84. [cssProp.prop]: between(cssProp.fromSize, cssProp.toSize, minScreen, maxScreen),
  85. },
  86. [`@media (min-width: ${maxScreen})`]: {
  87. [cssProp.prop]: cssProp.toSize,
  88. },
  89. }
  90. }
  91. }