directionalProperty.js.flow 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. // @flow
  2. import capitalizeString from '../internalHelpers/_capitalizeString'
  3. import type { Styles } from '../types/style'
  4. const positionMap = ['Top', 'Right', 'Bottom', 'Left']
  5. function generateProperty(property: string, position: string) {
  6. if (!property) return position.toLowerCase()
  7. const splitProperty = property.split('-')
  8. if (splitProperty.length > 1) {
  9. splitProperty.splice(1, 0, position)
  10. return splitProperty.reduce((acc, val) => `${acc}${capitalizeString(val)}`)
  11. }
  12. const joinedProperty = property.replace(/([a-z])([A-Z])/g, `$1${position}$2`)
  13. return property === joinedProperty ? `${property}${position}` : joinedProperty
  14. }
  15. function generateStyles(property: string, valuesWithDefaults: Array<?string | ?number>) {
  16. const styles = {}
  17. for (let i = 0; i < valuesWithDefaults.length; i += 1) {
  18. if (valuesWithDefaults[i] || valuesWithDefaults[i] === 0) {
  19. styles[generateProperty(property, positionMap[i])] = valuesWithDefaults[i]
  20. }
  21. }
  22. return styles
  23. }
  24. /**
  25. * Enables shorthand for direction-based properties. It accepts a property (hyphenated or camelCased) and up to four values that map to top, right, bottom, and left, respectively. You can optionally pass an empty string to get only the directional values as properties. You can also optionally pass a null argument for a directional value to ignore it.
  26. * @example
  27. * // Styles as object usage
  28. * const styles = {
  29. * ...directionalProperty('padding', '12px', '24px', '36px', '48px')
  30. * }
  31. *
  32. * // styled-components usage
  33. * const div = styled.div`
  34. * ${directionalProperty('padding', '12px', '24px', '36px', '48px')}
  35. * `
  36. *
  37. * // CSS as JS Output
  38. *
  39. * div {
  40. * 'paddingTop': '12px',
  41. * 'paddingRight': '24px',
  42. * 'paddingBottom': '36px',
  43. * 'paddingLeft': '48px'
  44. * }
  45. */
  46. export default function directionalProperty(
  47. property: string,
  48. ...values: Array<?string | ?number>
  49. ): Styles {
  50. // prettier-ignore
  51. const [firstValue, secondValue = firstValue, thirdValue = firstValue, fourthValue = secondValue] = values
  52. const valuesWithDefaults = [firstValue, secondValue, thirdValue, fourthValue]
  53. return generateStyles(property, valuesWithDefaults)
  54. }