breakpoints.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. let gridBreakpoints = {}
  2. //
  3. // Helper Functions
  4. //
  5. function lookupVariable(context, variableName) {
  6. const { frames, importantScope } = context
  7. return tree.Variable.prototype.find(frames, frame => {
  8. const { value, important } = frame.variable(variableName) || {}
  9. if (value === undefined)
  10. return
  11. if (important && importantScope[importantScope.length - 1])
  12. importantScope[importantScope.length - 1].important = important
  13. return value.eval(context)
  14. })
  15. }
  16. // @TODO: [@calvinjuarez] unify this function between files, maybe even canonize it as a
  17. // `Ruleset`/`DetachedRuleset` method at some point.
  18. function rulesetToMap(context, { ruleset: { rules } } = { ruleset: { rules: [] } }) {
  19. const map = {}
  20. rules.forEach(rule => {
  21. // Not exactly sure how to handle other types (or if they should be handled at all).
  22. if (! (rule instanceof tree.Declaration))
  23. return
  24. const { name: key, value } = rule.eval(context)
  25. map[key] = value
  26. })
  27. return map
  28. }
  29. function getBreakpoints(context, breakpoints) {
  30. if (! breakpoints) {
  31. if (Object.keys(gridBreakpoints).length === 0)
  32. gridBreakpoints = lookupVariable(context, '@grid-breakpoints')
  33. breakpoints = gridBreakpoints
  34. }
  35. const rulesetMap = rulesetToMap(context, breakpoints)
  36. // Since values in the map will be instances of `Anonymous`, convert them to `Dimension`s.
  37. for (const key in rulesetMap) {
  38. const value = rulesetMap[key].value
  39. const number = parseFloat(value, 10)
  40. const unit = value.toString().replace(number, '')
  41. rulesetMap[key] = new tree.Dimension(number, unit)
  42. }
  43. return rulesetMap
  44. }
  45. //
  46. // Less Functions
  47. //
  48. functions.add('breakpoint-next', function ({ value: breakpointName }, breakpoints) {
  49. const breakpointsMap = getBreakpoints(this.context, breakpoints)
  50. const breakpointNames = Object.keys(breakpointsMap)
  51. const breakpointIndex = breakpointNames.indexOf(breakpointName)
  52. if (breakpointIndex === -1)
  53. return new tree.Quoted('"')
  54. // Next breakpoint is null for the last breakpoint.
  55. if ((breakpointIndex + 1) === breakpointNames.length)
  56. return new tree.Quoted('"')
  57. return new tree.Quoted('"', breakpointNames[breakpointIndex + 1])
  58. })
  59. functions.add('breakpoint-min', function ({ value: breakpointName }, breakpoints) {
  60. const breakpointsMap = getBreakpoints(this.context, breakpoints)
  61. const breakpointNames = Object.keys(breakpointsMap)
  62. const breakpointIndex = breakpointNames.indexOf(breakpointName)
  63. if (breakpointIndex === -1)
  64. return new tree.Quoted('"')
  65. // Minumum breakpoint width is null for the first breakpoint.
  66. if (breakpointIndex === 0)
  67. return new tree.Quoted('"')
  68. return breakpointsMap[breakpointName]
  69. })
  70. functions.add('breakpoint-max', function ({ value: breakpointName }, breakpoints) {
  71. const breakpointsMap = getBreakpoints(this.context, breakpoints)
  72. const breakpointNames = Object.keys(breakpointsMap)
  73. const breakpointIndex = breakpointNames.indexOf(breakpointName)
  74. if (breakpointIndex === -1)
  75. return new tree.Quoted('"')
  76. // Maximum breakpoint width is null for the last breakpoint.
  77. if ((breakpointIndex + 1) === breakpointNames.length)
  78. return new tree.Quoted('"')
  79. const nextBreakpoint = breakpointsMap[breakpointNames[breakpointIndex + 1]]
  80. return new tree.Dimension(nextBreakpoint.value - 0.02, nextBreakpoint.unit)
  81. })
  82. functions.add('breakpoint-infix', function ({ value: breakpointName }, breakpoints) {
  83. const breakpointsMap = getBreakpoints(this.context, breakpoints)
  84. const breakpointNames = Object.keys(breakpointsMap)
  85. const breakpointIndex = breakpointNames.indexOf(breakpointName)
  86. if (breakpointIndex === -1)
  87. return new tree.Quoted('"')
  88. // Breakpoint infix is null the first breakpoint.
  89. if (breakpointIndex === 0)
  90. return new tree.Quoted('"')
  91. return new tree.Quoted('"', `-${breakpointName}`)
  92. })