forked from vuejs/vue-test-utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcreate-scoped-slots.js
97 lines (89 loc) · 2.56 KB
/
create-scoped-slots.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// @flow
import { compileToFunctions } from 'vue-template-compiler'
import { throwError } from 'shared/util'
import { VUE_VERSION } from 'shared/consts'
function isDestructuringSlotScope(slotScope: string): boolean {
return slotScope[0] === '{' && slotScope[slotScope.length - 1] === '}'
}
function getVueTemplateCompilerHelpers(
_Vue: Component
): { [name: string]: Function } {
// $FlowIgnore
const vue = new _Vue()
const helpers = {}
const names = [
'_c',
'_o',
'_n',
'_s',
'_l',
'_t',
'_q',
'_i',
'_m',
'_f',
'_k',
'_b',
'_v',
'_e',
'_u',
'_g'
]
names.forEach(name => {
helpers[name] = vue._renderProxy[name]
})
helpers.$createElement = vue._renderProxy.$createElement
helpers.$set = vue._renderProxy.$set
return helpers
}
function validateEnvironment(): void {
if (VUE_VERSION < 2.1) {
throwError(`the scopedSlots option is only supported in [email protected]+.`)
}
}
const slotScopeRe = /<[^>]+ slot-scope=\"(.+)\"/
// Hide warning about <template> disallowed as root element
function customWarn(msg) {
if (msg.indexOf('Cannot use <template> as component root element') === -1) {
console.error(msg)
}
}
export default function createScopedSlots(
scopedSlotsOption: ?{ [slotName: string]: string | Function },
_Vue: Component
): {
[slotName: string]: (props: Object) => VNode | Array<VNode>
} {
const scopedSlots = {}
if (!scopedSlotsOption) {
return scopedSlots
}
validateEnvironment()
const helpers = getVueTemplateCompilerHelpers(_Vue)
for (const scopedSlotName in scopedSlotsOption) {
const slot = scopedSlotsOption[scopedSlotName]
const isFn = typeof slot === 'function'
// Type check to silence flow (can't use isFn)
const renderFn =
typeof slot === 'function'
? slot
: compileToFunctions(slot, { warn: customWarn }).render
const hasSlotScopeAttr = !isFn && slot.match(slotScopeRe)
const slotScope = hasSlotScopeAttr && hasSlotScopeAttr[1]
scopedSlots[scopedSlotName] = function(props) {
let res
if (isFn) {
res = renderFn.call({ ...helpers }, props)
} else if (slotScope && !isDestructuringSlotScope(slotScope)) {
res = renderFn.call({ ...helpers, [slotScope]: props })
} else if (slotScope && isDestructuringSlotScope(slotScope)) {
res = renderFn.call({ ...helpers, ...props })
} else {
res = renderFn.call({ ...helpers, props })
}
// res is Array if <template> is a root element
return Array.isArray(res) ? res[0] : res
}
}
return scopedSlots
}