UNPKG

vuetify

Version:

Vue Material Component Framework

162 lines (144 loc) 4.82 kB
/** * @copyright 2017 Alex Regan * @license MIT * @see https://github.com/alexsasharegan/vue-functional-data-merge */ /* eslint-disable max-statements */ import { VNodeData } from 'vue' import { camelize, wrapInArray } from './helpers' const pattern = { styleList: /;(?![^(]*\))/g, styleProp: /:(.*)/, } as const function parseStyle (style: string) { const styleMap: Dictionary<any> = {} for (const s of style.split(pattern.styleList)) { let [key, val] = s.split(pattern.styleProp) key = key.trim() if (!key) { continue } // May be undefined if the `key: value` pair is incomplete. if (typeof val === 'string') { val = val.trim() } styleMap[camelize(key)] = val } return styleMap } /** * Intelligently merges data for createElement. * Merges arguments left to right, preferring the right argument. * Returns new VNodeData object. */ export default function mergeData (...vNodeData: VNodeData[]): VNodeData export default function mergeData (): VNodeData { const mergeTarget: VNodeData & Dictionary<any> = {} let i: number = arguments.length let prop: string // Allow for variadic argument length. while (i--) { // Iterate through the data properties and execute merge strategies // Object.keys eliminates need for hasOwnProperty call for (prop of Object.keys(arguments[i])) { switch (prop) { // Array merge strategy (array concatenation) case 'class': case 'directives': if (arguments[i][prop]) { mergeTarget[prop] = mergeClasses(mergeTarget[prop], arguments[i][prop]) } break case 'style': if (arguments[i][prop]) { mergeTarget[prop] = mergeStyles(mergeTarget[prop], arguments[i][prop]) } break // Space delimited string concatenation strategy case 'staticClass': if (!arguments[i][prop]) { break } if (mergeTarget[prop] === undefined) { mergeTarget[prop] = '' } if (mergeTarget[prop]) { // Not an empty string, so concatenate mergeTarget[prop] += ' ' } mergeTarget[prop] += arguments[i][prop].trim() break // Object, the properties of which to merge via array merge strategy (array concatenation). // Callback merge strategy merges callbacks to the beginning of the array, // so that the last defined callback will be invoked first. // This is done since to mimic how Object.assign merging // uses the last given value to assign. case 'on': case 'nativeOn': if (arguments[i][prop]) { mergeTarget[prop] = mergeListeners(mergeTarget[prop], arguments[i][prop]) } break // Object merge strategy case 'attrs': case 'props': case 'domProps': case 'scopedSlots': case 'staticStyle': case 'hook': case 'transition': if (!arguments[i][prop]) { break } if (!mergeTarget[prop]) { mergeTarget[prop] = {} } mergeTarget[prop] = { ...arguments[i][prop], ...mergeTarget[prop] } break // Reassignment strategy (no merge) default: // slot, key, ref, tag, show, keepAlive if (!mergeTarget[prop]) { mergeTarget[prop] = arguments[i][prop] } } } } return mergeTarget } export function mergeStyles ( target: undefined | string | object[] | object, source: undefined | string | object[] | object ) { if (!target) return source if (!source) return target target = wrapInArray(typeof target === 'string' ? parseStyle(target) : target) return (target as object[]).concat(typeof source === 'string' ? parseStyle(source) : source) } export function mergeClasses (target: any, source: any) { if (!source) return target if (!target) return source return target ? wrapInArray(target).concat(source) : source } export function mergeListeners (...args: [ { [key: string]: Function | Function[] } | undefined, { [key: string]: Function | Function[] } | undefined ]) { if (!args[0]) return args[1] if (!args[1]) return args[0] const dest: { [key: string]: Function | Function[] } = {} for (let i = 2; i--;) { const arg = args[i] for (const event in arg) { if (!arg[event]) continue if (dest[event]) { // Merge current listeners before (because we are iterating backwards). // Note that neither "target" or "source" must be altered. dest[event] = ([] as Function[]).concat(arg[event], dest[event]) } else { // Straight assign. dest[event] = arg[event] } } } return dest }