between.js.flow 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. // @flow
  2. import getValueAndUnit from '../helpers/getValueAndUnit'
  3. import PolishedError from '../internalHelpers/_errors'
  4. /**
  5. * Returns a CSS calc formula for linear interpolation of a property between two values. Accepts optional minScreen (defaults to '320px') and maxScreen (defaults to '1200px').
  6. *
  7. * @example
  8. * // Styles as object usage
  9. * const styles = {
  10. * fontSize: between('20px', '100px', '400px', '1000px'),
  11. * fontSize: between('20px', '100px')
  12. * }
  13. *
  14. * // styled-components usage
  15. * const div = styled.div`
  16. * fontSize: ${between('20px', '100px', '400px', '1000px')};
  17. * fontSize: ${between('20px', '100px')}
  18. * `
  19. *
  20. * // CSS as JS Output
  21. *
  22. * h1: {
  23. * 'fontSize': 'calc(-33.33333333333334px + 13.333333333333334vw)',
  24. * 'fontSize': 'calc(-9.090909090909093px + 9.090909090909092vw)'
  25. * }
  26. */
  27. export default function between(
  28. fromSize: string | number,
  29. toSize: string | number,
  30. minScreen?: string = '320px',
  31. maxScreen?: string = '1200px',
  32. ): string {
  33. const [unitlessFromSize, fromSizeUnit] = getValueAndUnit(fromSize)
  34. const [unitlessToSize, toSizeUnit] = getValueAndUnit(toSize)
  35. const [unitlessMinScreen, minScreenUnit] = getValueAndUnit(minScreen)
  36. const [unitlessMaxScreen, maxScreenUnit] = getValueAndUnit(maxScreen)
  37. if (
  38. typeof unitlessMinScreen !== 'number'
  39. || typeof unitlessMaxScreen !== 'number'
  40. || !minScreenUnit
  41. || !maxScreenUnit
  42. || minScreenUnit !== maxScreenUnit
  43. ) {
  44. throw new PolishedError(47)
  45. }
  46. if (
  47. typeof unitlessFromSize !== 'number'
  48. || typeof unitlessToSize !== 'number'
  49. || fromSizeUnit !== toSizeUnit
  50. ) {
  51. throw new PolishedError(48)
  52. }
  53. if (fromSizeUnit !== minScreenUnit || toSizeUnit !== maxScreenUnit) {
  54. throw new PolishedError(76)
  55. }
  56. const slope = (unitlessFromSize - unitlessToSize) / (unitlessMinScreen - unitlessMaxScreen)
  57. const base = unitlessToSize - slope * unitlessMaxScreen
  58. return `calc(${base.toFixed(2)}${fromSizeUnit || ''} + ${(100 * slope).toFixed(2)}vw)`
  59. }