1 1
import './VGrid.sass'
2

3 1
import Vue, { VNode, PropOptions } from 'vue'
4 1
import mergeData from '../../util/mergeData'
5 1
import { upperFirst } from '../../util/helpers'
6

7
// no xs
8 1
const breakpoints = ['sm', 'md', 'lg', 'xl']
9

10 1
const breakpointProps = (() => {
11 1
  return breakpoints.reduce((props, val) => {
12 1
    props[val] = {
13
      type: [Boolean, String, Number],
14
      default: false,
15
    }
16 1
    return props
17
  }, {} as Dictionary<PropOptions>)
18
})()
19

20 1
const offsetProps = (() => {
21 1
  return breakpoints.reduce((props, val) => {
22 1
    props['offset' + upperFirst(val)] = {
23
      type: [String, Number],
24
      default: null,
25
    }
26 1
    return props
27
  }, {} as Dictionary<PropOptions>)
28
})()
29

30 1
const orderProps = (() => {
31 1
  return breakpoints.reduce((props, val) => {
32 1
    props['order' + upperFirst(val)] = {
33
      type: [String, Number],
34
      default: null,
35
    }
36 1
    return props
37
  }, {} as Dictionary<PropOptions>)
38
})()
39

40 1
const propMap = {
41
  col: Object.keys(breakpointProps),
42
  offset: Object.keys(offsetProps),
43
  order: Object.keys(orderProps),
44
}
45

46 1
function breakpointClass (type: keyof typeof propMap, prop: string, val: boolean | string | number) {
47 1
  let className = type
48 1
  if (val == null || val === false) {
49 1
    return undefined
50
  }
51 1
  if (prop) {
52 1
    const breakpoint = prop.replace(type, '')
53 1
    className += `-${breakpoint}`
54
  }
55
  // Handling the boolean style prop when accepting [Boolean, String, Number]
56
  // means Vue will not convert <v-col sm></v-col> to sm: true for us.
57
  // Since the default is false, an empty string indicates the prop's presence.
58 1
  if (type === 'col' && (val === '' || val === true)) {
59
    // .col-md
60 1
    return className.toLowerCase()
61
  }
62
  // .order-md-6
63 1
  className += `-${val}`
64 1
  return className.toLowerCase()
65
}
66

67 1
const cache = new Map<string, any[]>()
68

69 1
export default Vue.extend({
70
  name: 'v-col',
71
  functional: true,
72
  props: {
73
    cols: {
74
      type: [Boolean, String, Number],
75
      default: false,
76
    },
77
    ...breakpointProps,
78
    offset: {
79
      type: [String, Number],
80
      default: null,
81
    },
82
    ...offsetProps,
83
    order: {
84
      type: [String, Number],
85
      default: null,
86
    },
87
    ...orderProps,
88
    alignSelf: {
89
      type: String,
90
      default: null,
91 1
      validator: (str: any) => ['auto', 'start', 'end', 'center', 'baseline', 'stretch'].includes(str),
92
    },
93
    tag: {
94
      type: String,
95
      default: 'div',
96
    },
97
  },
98 1
  render (h, { props, data, children, parent }): VNode {
99
    // Super-fast memoization based on props, 5x faster than JSON.stringify
100 1
    let cacheKey = ''
101 1
    for (const prop in props) {
102 1
      cacheKey += String((props as any)[prop])
103
    }
104 1
    let classList = cache.get(cacheKey)
105

106 1
    if (!classList) {
107 1
      classList = []
108
      // Loop through `col`, `offset`, `order` breakpoint props
109
      let type: keyof typeof propMap
110 1
      for (type in propMap) {
111 1
        propMap[type].forEach(prop => {
112 1
          const value: string | number | boolean = (props as any)[prop]
113 1
          const className = breakpointClass(type, prop, value)
114 1
          if (className) classList!.push(className)
115
        })
116
      }
117

118 1
      const hasColClasses = classList.some(className => className.startsWith('col-'))
119

120 1
      classList.push({
121
        // Default to .col if no other col-{bp}-* classes generated nor `cols` specified.
122 1
        col: !hasColClasses || !props.cols,
123
        [`col-${props.cols}`]: props.cols,
124
        [`offset-${props.offset}`]: props.offset,
125
        [`order-${props.order}`]: props.order,
126
        [`align-self-${props.alignSelf}`]: props.alignSelf,
127
      })
128

129 1
      cache.set(cacheKey, classList)
130
    }
131

132 1
    return h(props.tag, mergeData(data, { class: classList }), children)
133
  },
134
})

Read our documentation on viewing source code .

Loading