vuetify
Version:
Vue Material Component Framework
139 lines (122 loc) • 3.48 kB
text/typescript
import './VGrid.sass'
import Vue, { PropOptions } from 'vue'
import mergeData from '../../util/mergeData'
import { upperFirst } from '../../util/helpers'
// no xs
const breakpoints = ['sm', 'md', 'lg', 'xl']
const ALIGNMENT = ['start', 'end', 'center']
function makeProps (prefix: string, def: () => PropOptions) {
return breakpoints.reduce((props, val) => {
props[prefix + upperFirst(val)] = def()
return props
}, {} as Dictionary<PropOptions>)
}
const alignValidator = (str: any) => [...ALIGNMENT, 'baseline', 'stretch'].includes(str)
const alignProps = makeProps('align', () => ({
type: String,
default: null,
validator: alignValidator,
}))
const justifyValidator = (str: any) => [...ALIGNMENT, 'space-between', 'space-around'].includes(str)
const justifyProps = makeProps('justify', () => ({
type: String,
default: null,
validator: justifyValidator,
}))
const alignContentValidator = (str: any) => [...ALIGNMENT, 'space-between', 'space-around', 'stretch'].includes(str)
const alignContentProps = makeProps('alignContent', () => ({
type: String,
default: null,
validator: alignContentValidator,
}))
const propMap = {
align: Object.keys(alignProps),
justify: Object.keys(justifyProps),
alignContent: Object.keys(alignContentProps),
}
const classMap = {
align: 'align',
justify: 'justify',
alignContent: 'align-content',
}
function breakpointClass (type: keyof typeof propMap, prop: string, val: string) {
let className = classMap[type]
if (val == null) {
return undefined
}
if (prop) {
// alignSm -> Sm
const breakpoint = prop.replace(type, '')
className += `-${breakpoint}`
}
// .align-items-sm-center
className += `-${val}`
return className.toLowerCase()
}
const cache = new Map<string, any[]>()
export default Vue.extend({
name: 'v-row',
functional: true,
props: {
tag: {
type: String,
default: 'div',
},
dense: Boolean,
noGutters: Boolean,
align: {
type: String,
default: null,
validator: alignValidator,
},
...alignProps,
justify: {
type: String,
default: null,
validator: justifyValidator,
},
...justifyProps,
alignContent: {
type: String,
default: null,
validator: alignContentValidator,
},
...alignContentProps,
},
render (h, { props, data, children }) {
// Super-fast memoization based on props, 5x faster than JSON.stringify
let cacheKey = ''
for (const prop in props) {
cacheKey += String((props as any)[prop])
}
let classList = cache.get(cacheKey)
if (!classList) {
classList = []
// Loop through `align`, `justify`, `alignContent` breakpoint props
let type: keyof typeof propMap
for (type in propMap) {
propMap[type].forEach(prop => {
const value: string = (props as any)[prop]
const className = breakpointClass(type, prop, value)
if (className) classList!.push(className)
})
}
classList.push({
'no-gutters': props.noGutters,
'row--dense': props.dense,
[`align-${props.align}`]: props.align,
[`justify-${props.justify}`]: props.justify,
[`align-content-${props.alignContent}`]: props.alignContent,
})
cache.set(cacheKey, classList)
}
return h(
props.tag,
mergeData(data, {
staticClass: 'row',
class: classList,
}),
children
)
},
})