import { patchClass } from './modules/class' import { patchStyle } from './modules/style' import { patchAttr } from './modules/attrs' import { patchDOMProp } from './modules/props' import { patchEvent } from './modules/events' import { isOn, isString, isFunction, isModelListener } from '@vue/shared' import { RendererOptions } from '@vue/runtime-core' const nativeOnRE = /^on[a-z]/ type DOMRendererOptions = RendererOptions export const forcePatchProp: DOMRendererOptions['forcePatchProp'] = (_, key) => key === 'value' export const patchProp: DOMRendererOptions['patchProp'] = ( el, key, prevValue, nextValue, isSVG = false, prevChildren, parentComponent, parentSuspense, unmountChildren ) => { switch (key) { // special case 'class': patchClass(el, nextValue, isSVG) break case 'style': patchStyle(el, prevValue, nextValue) break default: if (isOn(key)) { // ignore v-model listeners if (!isModelListener(key)) { patchEvent(el, key, prevValue, nextValue, parentComponent) } } else if (shouldSetAsProp(el, key, nextValue, isSVG)) { patchDOMProp( el, key, nextValue, prevChildren, parentComponent, parentSuspense, unmountChildren ) } else { // special case for with // :true-value & :false-value // store value as dom properties since non-string values will be // stringified. if (key === 'true-value') { ;(el as any)._trueValue = nextValue } else if (key === 'false-value') { ;(el as any)._falseValue = nextValue } patchAttr(el, key, nextValue, isSVG) } break } } function shouldSetAsProp( el: Element, key: string, value: unknown, isSVG: boolean ) { if (isSVG) { // most keys must be set as attribute on svg elements to work // ...except innerHTML if (key === 'innerHTML') { return true } // or native onclick with function values if (key in el && nativeOnRE.test(key) && isFunction(value)) { return true } return false } // spellcheck and draggable are numerated attrs, however their // corresponding DOM properties are actually booleans - this leads to // setting it with a string "false" value leading it to be coerced to // `true`, so we need to always treat them as attributes. // Note that `contentEditable` doesn't have this problem: its DOM // property is also enumerated string values. if (key === 'spellcheck' || key === 'draggable') { return false } // #1787 form as an attribute must be a string, while it accepts an Element as // a prop if (key === 'form' && typeof value === 'string') { return false } // #1526 must be set as attribute if (key === 'list' && el.tagName === 'INPUT') { return false } // native onclick with string value, must be set as attribute if (nativeOnRE.test(key) && isString(value)) { return false } return key in el }