UNPKG

vuetify

Version:

Vue Material Component Framework

135 lines (120 loc) 3.65 kB
import './VGrid.sass' import Vue, { VNode, PropOptions } from 'vue' import mergeData from '../../util/mergeData' import { upperFirst } from '../../util/helpers' // no xs const breakpoints = ['sm', 'md', 'lg', 'xl'] const breakpointProps = (() => { return breakpoints.reduce((props, val) => { props[val] = { type: [Boolean, String, Number], default: false, } return props }, {} as Dictionary<PropOptions>) })() const offsetProps = (() => { return breakpoints.reduce((props, val) => { props['offset' + upperFirst(val)] = { type: [String, Number], default: null, } return props }, {} as Dictionary<PropOptions>) })() const orderProps = (() => { return breakpoints.reduce((props, val) => { props['order' + upperFirst(val)] = { type: [String, Number], default: null, } return props }, {} as Dictionary<PropOptions>) })() const propMap = { col: Object.keys(breakpointProps), offset: Object.keys(offsetProps), order: Object.keys(orderProps), } function breakpointClass (type: keyof typeof propMap, prop: string, val: boolean | string | number) { let className = type if (val == null || val === false) { return undefined } if (prop) { const breakpoint = prop.replace(type, '') className += `-${breakpoint}` } // Handling the boolean style prop when accepting [Boolean, String, Number] // means Vue will not convert <v-col sm></v-col> to sm: true for us. // Since the default is false, an empty string indicates the prop's presence. if (type === 'col' && (val === '' || val === true)) { // .col-md return className.toLowerCase() } // .order-md-6 className += `-${val}` return className.toLowerCase() } const cache = new Map<string, any[]>() export default Vue.extend({ name: 'v-col', functional: true, props: { cols: { type: [Boolean, String, Number], default: false, }, ...breakpointProps, offset: { type: [String, Number], default: null, }, ...offsetProps, order: { type: [String, Number], default: null, }, ...orderProps, alignSelf: { type: String, default: null, validator: (str: any) => ['auto', 'start', 'end', 'center', 'baseline', 'stretch'].includes(str), }, tag: { type: String, default: 'div', }, }, render (h, { props, data, children, parent }): VNode { // 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 `col`, `offset`, `order` breakpoint props let type: keyof typeof propMap for (type in propMap) { propMap[type].forEach(prop => { const value: string | number | boolean = (props as any)[prop] const className = breakpointClass(type, prop, value) if (className) classList!.push(className) }) } const hasColClasses = classList.some(className => className.startsWith('col-')) classList.push({ // Default to .col if no other col-{bp}-* classes generated nor `cols` specified. col: !hasColClasses || !props.cols, [`col-${props.cols}`]: props.cols, [`offset-${props.offset}`]: props.offset, [`order-${props.order}`]: props.order, [`align-self-${props.alignSelf}`]: props.alignSelf, }) cache.set(cacheKey, classList) } return h(props.tag, mergeData(data, { class: classList }), children) }, })