chore: fix setStyle and tests

This commit is contained in:
Evan You 2024-12-12 22:02:30 +08:00
parent c4b853d997
commit e38805354d
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
2 changed files with 39 additions and 43 deletions

View File

@ -9,7 +9,7 @@ import {
setText, setText,
setValue, setValue,
} from '../../src/dom/prop' } from '../../src/dom/prop'
import { setStyle } from '../../src/dom/style' import { setStyle } from '../../src/dom/prop'
import { VaporComponentInstance } from '../../src/component' import { VaporComponentInstance } from '../../src/component'
import { currentInstance, simpleSetCurrentInstance } from '@vue/runtime-dom' import { currentInstance, simpleSetCurrentInstance } from '@vue/runtime-dom'
@ -42,87 +42,83 @@ describe('patchProp', () => {
describe('setStyle', () => { describe('setStyle', () => {
test('should set style', () => { test('should set style', () => {
const el = document.createElement('div') const el = document.createElement('div')
setStyle(el, '', 'color: red') setStyle(el, 'color: red')
expect(el.style.cssText).toBe('color: red;') expect(el.style.cssText).toBe('color: red;')
}) })
test('should work with camelCase', () => { test('should work with camelCase', () => {
const el = document.createElement('div') const el = document.createElement('div')
setStyle(el, null, { fontSize: '12px' }) setStyle(el, { fontSize: '12px' })
expect(el.style.cssText).toBe('font-size: 12px;') expect(el.style.cssText).toBe('font-size: 12px;')
}) })
test('shoud set style with object and array property', () => { test('shoud set style with object and array property', () => {
const el = document.createElement('div') const el = document.createElement('div')
let prev: any setStyle(el, { color: 'red' })
prev = setStyle(el, prev, { color: 'red' })
expect(el.style.cssText).toBe('color: red;') expect(el.style.cssText).toBe('color: red;')
setStyle(el, prev, [{ color: 'blue' }, { fontSize: '12px' }]) setStyle(el, [{ color: 'blue' }, { fontSize: '12px' }])
expect(el.style.cssText).toBe('color: blue; font-size: 12px;') expect(el.style.cssText).toBe('color: blue; font-size: 12px;')
}) })
test('should remove if falsy value', () => { test('should remove if falsy value', () => {
const el = document.createElement('div') const el = document.createElement('div')
let prev setStyle(el, { color: undefined, borderRadius: null })
prev = setStyle(el, prev, { color: undefined, borderRadius: null })
expect(el.style.cssText).toBe('') expect(el.style.cssText).toBe('')
prev = setStyle(el, prev, { color: 'red' }) setStyle(el, { color: 'red' })
expect(el.style.cssText).toBe('color: red;') expect(el.style.cssText).toBe('color: red;')
setStyle(el, prev, { color: undefined, borderRadius: null }) setStyle(el, { color: undefined, borderRadius: null })
expect(el.style.cssText).toBe('') expect(el.style.cssText).toBe('')
}) })
test('should work with !important', () => { test('should work with !important', () => {
const el = document.createElement('div') const el = document.createElement('div')
setStyle(el, null, { color: 'red !important' }) setStyle(el, { color: 'red !important' })
expect(el.style.cssText).toBe('color: red !important;') expect(el.style.cssText).toBe('color: red !important;')
}) })
test('should work with camelCase and !important', () => { test('should work with camelCase and !important', () => {
const el = document.createElement('div') const el = document.createElement('div')
setStyle(el, null, { fontSize: '12px !important' }) setStyle(el, { fontSize: '12px !important' })
expect(el.style.cssText).toBe('font-size: 12px !important;') expect(el.style.cssText).toBe('font-size: 12px !important;')
}) })
test('should work with multiple entries', () => { test('should work with multiple entries', () => {
const el = document.createElement('div') const el = document.createElement('div')
setStyle(el, null, { color: 'red', marginRight: '10px' }) setStyle(el, { color: 'red', marginRight: '10px' })
expect(el.style.getPropertyValue('color')).toBe('red') expect(el.style.getPropertyValue('color')).toBe('red')
expect(el.style.getPropertyValue('margin-right')).toBe('10px') expect(el.style.getPropertyValue('margin-right')).toBe('10px')
}) })
test('should patch with falsy style value', () => { test('should patch with falsy style value', () => {
const el = document.createElement('div') const el = document.createElement('div')
let prev: any setStyle(el, { width: '100px' })
prev = setStyle(el, prev, { width: '100px' })
expect(el.style.cssText).toBe('width: 100px;') expect(el.style.cssText).toBe('width: 100px;')
prev = setStyle(el, prev, { width: 0 }) setStyle(el, { width: 0 })
expect(el.style.cssText).toBe('width: 0px;') expect(el.style.cssText).toBe('width: 0px;')
}) })
test('should remove style attribute on falsy value', () => { test('should remove style attribute on falsy value', () => {
const el = document.createElement('div') const el = document.createElement('div')
let prev: any setStyle(el, { width: '100px' })
prev = setStyle(el, prev, { width: '100px' })
expect(el.style.cssText).toBe('width: 100px;') expect(el.style.cssText).toBe('width: 100px;')
prev = setStyle(el, prev, { width: undefined }) setStyle(el, { width: undefined })
expect(el.style.cssText).toBe('') expect(el.style.cssText).toBe('')
prev = setStyle(el, prev, { width: '100px' }) setStyle(el, { width: '100px' })
expect(el.style.cssText).toBe('width: 100px;') expect(el.style.cssText).toBe('width: 100px;')
setStyle(el, prev, null) setStyle(el, null)
expect(el.hasAttribute('style')).toBe(false) expect(el.hasAttribute('style')).toBe(false)
expect(el.style.cssText).toBe('') expect(el.style.cssText).toBe('')
}) })
test('should warn for trailing semicolons', () => { test('should warn for trailing semicolons', () => {
const el = document.createElement('div') const el = document.createElement('div')
setStyle(el, null, { color: 'red;' }) setStyle(el, { color: 'red;' })
expect( expect(
`Unexpected semicolon at the end of 'color' style value: 'red;'`, `Unexpected semicolon at the end of 'color' style value: 'red;'`,
).toHaveBeenWarned() ).toHaveBeenWarned()
setStyle(el, null, { '--custom': '100; ' }) setStyle(el, { '--custom': '100; ' })
expect( expect(
`Unexpected semicolon at the end of '--custom' style value: '100; '`, `Unexpected semicolon at the end of '--custom' style value: '100; '`,
).toHaveBeenWarned() ).toHaveBeenWarned()
@ -130,13 +126,13 @@ describe('patchProp', () => {
test('should not warn for trailing semicolons', () => { test('should not warn for trailing semicolons', () => {
const el = document.createElement('div') const el = document.createElement('div')
setStyle(el, null, { '--custom': '100\\;' }) setStyle(el, { '--custom': '100\\;' })
expect(el.style.getPropertyValue('--custom')).toBe('100\\;') expect(el.style.getPropertyValue('--custom')).toBe('100\\;')
}) })
test('should work with shorthand properties', () => { test('should work with shorthand properties', () => {
const el = document.createElement('div') const el = document.createElement('div')
setStyle(el, null, { setStyle(el, {
borderBottom: '1px solid red', borderBottom: '1px solid red',
border: '1px solid green', border: '1px solid green',
}) })
@ -164,25 +160,29 @@ describe('patchProp', () => {
test('should work with css custom properties', () => { test('should work with css custom properties', () => {
const el = mockElementWithStyle() const el = mockElementWithStyle()
setStyle(el as any, null, { '--theme': 'red' }) setStyle(el as any, { '--theme': 'red' })
expect(el.style.getPropertyValue('--theme')).toBe('red') expect(el.style.getPropertyValue('--theme')).toBe('red')
}) })
test('should auto vendor prefixing', () => { test('should auto vendor prefixing', () => {
const el = mockElementWithStyle() const el = mockElementWithStyle()
setStyle(el as any, null, { transition: 'all 1s' }) setStyle(el as any, { transition: 'all 1s' })
expect(el.style.WebkitTransition).toBe('all 1s') expect(el.style.WebkitTransition).toBe('all 1s')
}) })
test('should work with multiple values', () => { test('should work with multiple values', () => {
const el = mockElementWithStyle() const el = mockElementWithStyle()
setStyle(el as any, null, { setStyle(el as any, {
display: ['-webkit-box', '-ms-flexbox', 'flex'], display: ['-webkit-box', '-ms-flexbox', 'flex'],
}) })
expect(el.style.display).toBe('flex') expect(el.style.display).toBe('flex')
}) })
}) })
describe.todo('setClassIncremental', () => {})
describe.todo('setStyleIncremental', () => {})
describe('setAttr', () => { describe('setAttr', () => {
test('should set attribute', () => { test('should set attribute', () => {
const el = document.createElement('div') const el = document.createElement('div')

View File

@ -9,19 +9,14 @@ import {
toDisplayString, toDisplayString,
} from '@vue/shared' } from '@vue/shared'
import { on } from './event' import { on } from './event'
import { import { mergeProps, patchStyle, shouldSetAsProp, warn } from '@vue/runtime-dom'
mergeProps,
patchStyle as setStyle,
shouldSetAsProp,
warn,
} from '@vue/runtime-dom'
type TargetElement = Element & { type TargetElement = Element & {
$html?: string $html?: string
$cls?: string $cls?: string
$clsi?: string $clsi?: string
$sty?: NormalizedStyle $sty?: NormalizedStyle | string | undefined
$styi?: NormalizedStyle $styi?: NormalizedStyle | undefined
$dprops?: Record<string, any> $dprops?: Record<string, any>
} }
@ -67,10 +62,11 @@ export function setClassIncremental(el: TargetElement, value: any): void {
} }
} }
/** export function setStyle(el: TargetElement, value: any): void {
* Reuse from runtime-dom const prev = el.$sty
*/ value = el.$sty = normalizeStyle(value)
export { setStyle } patchStyle(el, prev, value)
}
/** /**
* A version of setStyle that does not overwrite pre-existing styles. * A version of setStyle that does not overwrite pre-existing styles.
@ -81,8 +77,8 @@ export function setStyleIncremental(el: TargetElement, value: any): void {
const prev = el.$styi const prev = el.$styi
value = el.$styi = isString(value) value = el.$styi = isString(value)
? parseStringStyle(value) ? parseStringStyle(value)
: ((normalizeStyle(value) || {}) as NormalizedStyle) : (normalizeStyle(value) as NormalizedStyle | undefined)
setStyle(el, prev, value) patchStyle(el, prev, value)
} }
export function setAttr(el: any, key: string, value: any): void { export function setAttr(el: any, key: string, value: any): void {
@ -218,7 +214,7 @@ export function setDynamicProp(
if (root) { if (root) {
setStyleIncremental(el, value) setStyleIncremental(el, value)
} else { } else {
setStyle(el, prev, value) setStyle(el, value)
} }
} else if (isOn(key)) { } else if (isOn(key)) {
on(el, key[2].toLowerCase() + key.slice(3), () => value, { effect: true }) on(el, key[2].toLowerCase() + key.slice(3), () => value, { effect: true })