+136
-20
lines changedFilter options
+136
-20
lines changed Original file line number Diff line number Diff line change
@@ -884,9 +884,9 @@ export default {
884
884
885
885
return (_ctx, _push, _parent, _attrs) => {
886
886
const _cssVars = { style: {
887
-
"--xxxxxxxx-count": (count.value),
888
-
"--xxxxxxxx-style\\\\.color": (style.color),
889
-
"--xxxxxxxx-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")
887
+
":--xxxxxxxx-count": (count.value),
888
+
":--xxxxxxxx-style\\\\.color": (style.color),
889
+
":--xxxxxxxx-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")
890
890
}}
891
891
_push(\`<!--[--><div\${
892
892
_ssrRenderAttrs(_cssVars)
Original file line number Diff line number Diff line change
@@ -652,10 +652,10 @@ describe('SFC compile <script setup>', () => {
652
652
expect(content).toMatch(`return (_ctx, _push`)
653
653
expect(content).toMatch(`ssrInterpolate`)
654
654
expect(content).not.toMatch(`useCssVars`)
655
-
expect(content).toMatch(`"--${mockId}-count": (count.value)`)
656
-
expect(content).toMatch(`"--${mockId}-style\\\\.color": (style.color)`)
655
+
expect(content).toMatch(`":--${mockId}-count": (count.value)`)
656
+
expect(content).toMatch(`":--${mockId}-style\\\\.color": (style.color)`)
657
657
expect(content).toMatch(
658
-
`"--${mockId}-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")`,
658
+
`":--${mockId}-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")`,
659
659
)
660
660
assertCode(content)
661
661
})
Original file line number Diff line number Diff line change
@@ -23,7 +23,12 @@ export function genCssVarsFromList(
23
23
return `{\n ${vars
24
24
.map(
25
25
key =>
26
-
`"${isSSR ? `--` : ``}${genVarName(id, key, isProd, isSSR)}": (${key})`,
26
+
// The `:` prefix here is used in `ssrRenderStyle` to distinguish whether
27
+
// a custom property comes from `ssrCssVars`. If it does, we need to reset
28
+
// its value to `initial` on the component instance to avoid unintentionally
29
+
// inheriting the same property value from a different instance of the same
30
+
// component in the outer scope.
31
+
`"${isSSR ? `:--` : ``}${genVarName(id, key, isProd, isSSR)}": (${key})`,
27
32
)
28
33
.join(',\n ')}\n}`
29
34
}
Original file line number Diff line number Diff line change
@@ -585,13 +585,13 @@ export interface ComponentInternalInstance {
585
585
* For updating css vars on contained teleports
586
586
* @internal
587
587
*/
588
-
ut?: (vars?: Record<string, string>) => void
588
+
ut?: (vars?: Record<string, unknown>) => void
589
589
590
590
/**
591
591
* dev only. For style v-bind hydration mismatch checks
592
592
* @internal
593
593
*/
594
-
getCssVars?: () => Record<string, string>
594
+
getCssVars?: () => Record<string, unknown>
595
595
596
596
/**
597
597
* v2 compat only, for caching mutated $options
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ import {
28
28
isReservedProp,
29
29
isString,
30
30
normalizeClass,
31
+
normalizeCssVarValue,
31
32
normalizeStyle,
32
33
stringifyStyle,
33
34
} from '@vue/shared'
@@ -945,10 +946,8 @@ function resolveCssVars(
945
946
) {
946
947
const cssVars = instance.getCssVars()
947
948
for (const key in cssVars) {
948
-
expectedMap.set(
949
-
`--${getEscapedCssVarName(key, false)}`,
950
-
String(cssVars[key]),
951
-
)
949
+
const value = normalizeCssVarValue(cssVars[key])
950
+
expectedMap.set(`--${getEscapedCssVarName(key, false)}`, value)
952
951
}
953
952
}
954
953
if (vnode === root && instance.parent) {
Original file line number Diff line number Diff line change
@@ -465,4 +465,27 @@ describe('useCssVars', () => {
465
465
render(h(App), root)
466
466
expect(colorInOnMount).toBe(`red`)
467
467
})
468
+
469
+
test('should set vars as `initial` for nullish values', async () => {
470
+
// `getPropertyValue` cannot reflect the real value for white spaces and JSDOM also
471
+
// doesn't 100% reflect the real behavior of browsers, so we only keep the test for
472
+
// `initial` value here.
473
+
// The value normalization is tested in packages/shared/__tests__/cssVars.spec.ts.
474
+
const state = reactive<Record<string, unknown>>({
475
+
foo: undefined,
476
+
bar: null,
477
+
})
478
+
const root = document.createElement('div')
479
+
const App = {
480
+
setup() {
481
+
useCssVars(() => state)
482
+
return () => h('div')
483
+
},
484
+
}
485
+
render(h(App), root)
486
+
await nextTick()
487
+
const style = (root.children[0] as HTMLElement).style
488
+
expect(style.getPropertyValue('--foo')).toBe('initial')
489
+
expect(style.getPropertyValue('--bar')).toBe('initial')
490
+
})
468
491
})
Original file line number Diff line number Diff line change
@@ -10,14 +10,16 @@ import {
10
10
warn,
11
11
watch,
12
12
} from '@vue/runtime-core'
13
-
import { NOOP, ShapeFlags } from '@vue/shared'
13
+
import { NOOP, ShapeFlags, normalizeCssVarValue } from '@vue/shared'
14
14
15
15
export const CSS_VAR_TEXT: unique symbol = Symbol(__DEV__ ? 'CSS_VAR_TEXT' : '')
16
16
/**
17
17
* Runtime helper for SFC's CSS variable injection feature.
18
18
* @private
19
19
*/
20
-
export function useCssVars(getter: (ctx: any) => Record<string, string>): void {
20
+
export function useCssVars(
21
+
getter: (ctx: any) => Record<string, unknown>,
22
+
): void {
21
23
if (!__BROWSER__ && !__TEST__) return
22
24
23
25
const instance = getCurrentInstance()
@@ -64,7 +66,7 @@ export function useCssVars(getter: (ctx: any) => Record<string, string>): void {
64
66
})
65
67
}
66
68
67
-
function setVarsOnVNode(vnode: VNode, vars: Record<string, string>) {
69
+
function setVarsOnVNode(vnode: VNode, vars: Record<string, unknown>) {
68
70
if (__FEATURE_SUSPENSE__ && vnode.shapeFlag & ShapeFlags.SUSPENSE) {
69
71
const suspense = vnode.suspense!
70
72
vnode = suspense.activeBranch!
@@ -94,13 +96,14 @@ function setVarsOnVNode(vnode: VNode, vars: Record<string, string>) {
94
96
}
95
97
}
96
98
97
-
function setVarsOnNode(el: Node, vars: Record<string, string>) {
99
+
function setVarsOnNode(el: Node, vars: Record<string, unknown>) {
98
100
if (el.nodeType === 1) {
99
101
const style = (el as HTMLElement).style
100
102
let cssText = ''
101
103
for (const key in vars) {
102
-
style.setProperty(`--${key}`, vars[key])
103
-
cssText += `--${key}: ${vars[key]};`
104
+
const value = normalizeCssVarValue(vars[key])
105
+
style.setProperty(`--${key}`, value)
106
+
cssText += `--${key}: ${value};`
104
107
}
105
108
;(style as any)[CSS_VAR_TEXT] = cssText
106
109
}
Original file line number Diff line number Diff line change
@@ -203,4 +203,19 @@ describe('ssr: renderStyle', () => {
203
203
}),
204
204
).toBe(`color:"><script;`)
205
205
})
206
+
207
+
test('useCssVars handling', () => {
208
+
expect(
209
+
ssrRenderStyle({
210
+
fontSize: null,
211
+
':--v1': undefined,
212
+
':--v2': null,
213
+
':--v3': '',
214
+
':--v4': ' ',
215
+
':--v5': 'foo',
216
+
':--v6': 0,
217
+
'--foo': 1,
218
+
}),
219
+
).toBe(`--v1:initial;--v2:initial;--v3: ;--v4: ;--v5:foo;--v6:0;--foo:1;`)
220
+
})
206
221
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
1
1
import {
2
2
escapeHtml,
3
+
isArray,
4
+
isObject,
3
5
isRenderableAttrValue,
4
6
isSVGTag,
5
7
stringifyStyle,
@@ -12,6 +14,7 @@ import {
12
14
isString,
13
15
makeMap,
14
16
normalizeClass,
17
+
normalizeCssVarValue,
15
18
normalizeStyle,
16
19
propsToAttrMap,
17
20
} from '@vue/shared'
@@ -93,6 +96,22 @@ export function ssrRenderStyle(raw: unknown): string {
93
96
if (isString(raw)) {
94
97
return escapeHtml(raw)
95
98
}
96
-
const styles = normalizeStyle(raw)
99
+
const styles = normalizeStyle(ssrResetCssVars(raw))
97
100
return escapeHtml(stringifyStyle(styles))
98
101
}
102
+
103
+
function ssrResetCssVars(raw: unknown) {
104
+
if (!isArray(raw) && isObject(raw)) {
105
+
const res: Record<string, unknown> = {}
106
+
for (const key in raw) {
107
+
// `:` prefixed keys are coming from `ssrCssVars`
108
+
if (key.startsWith(':--')) {
109
+
res[key.slice(1)] = normalizeCssVarValue(raw[key])
110
+
} else {
111
+
res[key] = raw[key]
112
+
}
113
+
}
114
+
return res
115
+
}
116
+
return raw
117
+
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
1
+
import { normalizeCssVarValue } from '../src'
2
+
3
+
describe('utils/cssVars', () => {
4
+
test('should normalize css binding values correctly', () => {
5
+
expect(normalizeCssVarValue(null)).toBe('initial')
6
+
expect(normalizeCssVarValue(undefined)).toBe('initial')
7
+
expect(normalizeCssVarValue('')).toBe(' ')
8
+
expect(normalizeCssVarValue(' ')).toBe(' ')
9
+
expect(normalizeCssVarValue('foo')).toBe('foo')
10
+
expect(normalizeCssVarValue(0)).toBe('0')
11
+
})
12
+
13
+
test('should warn on invalid css binding values', () => {
14
+
const warning =
15
+
'[Vue warn] Invalid value used for CSS binding. Expected a string or a finite number but received:'
16
+
expect(normalizeCssVarValue(NaN)).toBe('NaN')
17
+
expect(warning).toHaveBeenWarnedTimes(1)
18
+
expect(normalizeCssVarValue(Infinity)).toBe('Infinity')
19
+
expect(warning).toHaveBeenWarnedTimes(2)
20
+
expect(normalizeCssVarValue(-Infinity)).toBe('-Infinity')
21
+
expect(warning).toHaveBeenWarnedTimes(3)
22
+
expect(normalizeCssVarValue({})).toBe('[object Object]')
23
+
expect(warning).toHaveBeenWarnedTimes(4)
24
+
expect(normalizeCssVarValue([])).toBe('')
25
+
expect(warning).toHaveBeenWarnedTimes(5)
26
+
})
27
+
})
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4