183 lines
4.4 KiB
TypeScript

import {
camelize,
extend,
hyphenate,
isArray,
isObject,
isReservedProp,
normalizeClass
} from '@vue/shared'
import { ComponentInternalInstance } from '../component'
import { Slot } from '../componentSlots'
import { createSlots } from '../helpers/createSlots'
import { renderSlot } from '../helpers/renderSlot'
import { toHandlers } from '../helpers/toHandlers'
import { mergeProps, VNode } from '../vnode'
function toObject(arr: Array<any>): Object {
const res = {}
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i])
}
}
return res
}
export function legacyBindObjectProps(
data: any,
_tag: string,
value: any,
_asProp: boolean,
isSync?: boolean
) {
if (value && isObject(value)) {
if (isArray(value)) {
value = toObject(value)
}
for (const key in value) {
if (isReservedProp(key)) {
data[key] = value[key]
} else if (key === 'class') {
data.class = normalizeClass([data.class, value.class])
} else if (key === 'style') {
data.style = normalizeClass([data.style, value.style])
} else {
const attrs = data.attrs || (data.attrs = {})
const camelizedKey = camelize(key)
const hyphenatedKey = hyphenate(key)
if (!(camelizedKey in attrs) && !(hyphenatedKey in attrs)) {
attrs[key] = value[key]
if (isSync) {
const on = data.on || (data.on = {})
on[`update:${key}`] = function ($event: any) {
value[key] = $event
}
}
}
}
}
}
return data
}
export function legacyBindObjectListeners(props: any, listeners: any) {
return mergeProps(props, toHandlers(listeners))
}
export function legacyRenderSlot(
instance: ComponentInternalInstance,
name: string,
fallback?: VNode[],
props?: any,
bindObject?: any
) {
if (bindObject) {
props = mergeProps(props, bindObject)
}
return renderSlot(instance.slots, name, props, fallback && (() => fallback))
}
type LegacyScopedSlotsData = Array<
| {
key: string
fn: Function
}
| LegacyScopedSlotsData
>
export function legacyresolveScopedSlots(
fns: LegacyScopedSlotsData,
raw?: Record<string, Slot>,
// the following are added in 2.6
hasDynamicKeys?: boolean
) {
// v2 default slot doesn't have name
return createSlots(
raw || ({ $stable: !hasDynamicKeys } as any),
mapKeyToName(fns)
)
}
function mapKeyToName(slots: LegacyScopedSlotsData) {
for (let i = 0; i < slots.length; i++) {
const fn = slots[i]
if (fn) {
if (isArray(fn)) {
mapKeyToName(fn)
} else {
;(fn as any).name = fn.key || 'default'
}
}
}
return slots as any
}
const staticCacheMap = /*#__PURE__*/ new WeakMap<
ComponentInternalInstance,
any[]
>()
export function legacyRenderStatic(
instance: ComponentInternalInstance,
index: number
) {
let cache = staticCacheMap.get(instance)
if (!cache) {
staticCacheMap.set(instance, (cache = []))
}
if (cache[index]) {
return cache[index]
}
const fn = (instance.type as any).staticRenderFns[index]
const ctx = instance.proxy
return (cache[index] = fn.call(ctx, null, ctx))
}
export function legacyCheckKeyCodes(
instance: ComponentInternalInstance,
eventKeyCode: number,
key: string,
builtInKeyCode?: number | number[],
eventKeyName?: string,
builtInKeyName?: string | string[]
) {
const config = instance.appContext.config as any
const configKeyCodes = config.keyCodes || {}
const mappedKeyCode = configKeyCodes[key] || builtInKeyCode
if (builtInKeyName && eventKeyName && !configKeyCodes[key]) {
return isKeyNotMatch(builtInKeyName, eventKeyName)
} else if (mappedKeyCode) {
return isKeyNotMatch(mappedKeyCode, eventKeyCode)
} else if (eventKeyName) {
return hyphenate(eventKeyName) !== key
}
}
function isKeyNotMatch<T>(expect: T | T[], actual: T): boolean {
if (isArray(expect)) {
return !expect.includes(actual)
} else {
return expect !== actual
}
}
export function legacyMarkOnce(tree: VNode) {
return tree
}
export function legacyBindDynamicKeys(props: any, values: any[]) {
for (let i = 0; i < values.length; i += 2) {
const key = values[i]
if (typeof key === 'string' && key) {
props[values[i]] = values[i + 1]
}
}
return props
}
export function legacyPrependModifier(value: any, symbol: string) {
return typeof value === 'string' ? symbol + value : value
}