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 { camelize, isFunction, isModelListener, isNativeOn, isOn, isString, shouldSetAsAttr, } from '@vue/shared' import type { RendererOptions } from '@vue/runtime-core' import type { VueElement } from './apiCustomElement' type DOMRendererOptions = RendererOptions export const patchProp: DOMRendererOptions['patchProp'] = ( el, key, prevValue, nextValue, namespace, parentComponent, ) => { const isSVG = namespace === 'svg' if (key === 'class') { patchClass(el, nextValue, isSVG) } else if (key === 'style') { patchStyle(el, prevValue, nextValue) } else if (isOn(key)) { // ignore v-model listeners if (!isModelListener(key)) { patchEvent(el, key, prevValue, nextValue, parentComponent) } } else if ( key[0] === '.' ? ((key = key.slice(1)), true) : key[0] === '^' ? ((key = key.slice(1)), false) : shouldSetAsProp(el, key, nextValue, isSVG) ) { patchDOMProp(el, key, nextValue, parentComponent) // #6007 also set form state as attributes so they work with // or libs / extensions that expect attributes // #11163 custom elements may use value as an prop and set it as object if ( !el.tagName.includes('-') && (key === 'value' || key === 'checked' || key === 'selected') ) { patchAttr(el, key, nextValue, isSVG, parentComponent, key !== 'value') } } else if ( // #11081 force set props for possible async custom element (el as VueElement)._isVueCE && (/[A-Z]/.test(key) || !isString(nextValue)) ) { patchDOMProp(el, camelize(key), nextValue, parentComponent, key) } 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, parentComponent) } } export function shouldSetAsProp( el: Element, key: string, value: unknown, isSVG: boolean, ): boolean { if (isSVG) { // most keys must be set as attribute on svg elements to work // ...except innerHTML & textContent if (key === 'innerHTML' || key === 'textContent') { return true } // or native onclick with function values if (key in el && isNativeOn(key) && isFunction(value)) { return true } return false } if (shouldSetAsAttr(el.tagName, key)) { return false } // native onclick with string value, must be set as attribute if (isNativeOn(key) && isString(value)) { return false } return key in el }