OPTIONS_BEFORE_DESTROY = 'OPTIONS_BEFORE_DESTROY',
OPTIONS_DESTROYED = 'OPTIONS_DESTROYED',
- V_ON_KEYCODE_MODIFIER = 'V_ON_KEYCODE_MODIFIER',
+ WATCH_ARRAY = 'WATCH_ARRAY',
PROPS_DEFAULT_THIS = 'PROPS_DEFAULT_THIS',
+
+ V_ON_KEYCODE_MODIFIER = 'V_ON_KEYCODE_MODIFIER',
CUSTOM_DIR = 'CUSTOM_DIR',
- WATCH_ARRAY = 'WATCH_ARRAY',
+
+ ATTR_FALSE_VALUE = 'ATTR_FALSE_VALUE',
+ ATTR_ENUMERATED_COERSION = 'ATTR_ENUMERATED_COERSION',
TRANSITION_CLASSES = 'TRANSITION_CLASSES',
TRANSITION_GROUP_ROOT = 'TRANSITION_GROUP_ROOT'
message: `\`destroyed\` has been renamed to \`unmounted\`.`
},
- [DeprecationTypes.V_ON_KEYCODE_MODIFIER]: {
+ [DeprecationTypes.WATCH_ARRAY]: {
message:
- `Using keyCode as v-on modifier is no longer supported. ` +
- `Use kebab-case key name modifiers instead.`,
- link: `https://v3.vuejs.org/guide/migration/keycode-modifiers.html`
+ `"watch" option or vm.$watch on an array value will no longer ` +
+ `trigger on array mutation unless the "deep" option is specified. ` +
+ `If current usage is intended, you can disable the compat behavior and ` +
+ `suppress this warning with:` +
+ `\n\n configureCompat({ ${
+ DeprecationTypes.WATCH_ARRAY
+ }: { enabled: false }})\n`,
+ link: `https://v3.vuejs.org/guide/migration/watch.html`
},
[DeprecationTypes.PROPS_DEFAULT_THIS]: {
link: `https://v3.vuejs.org/guide/migration/custom-directives.html`
},
- [DeprecationTypes.WATCH_ARRAY]: {
+ [DeprecationTypes.V_ON_KEYCODE_MODIFIER]: {
message:
- `"watch" option or vm.$watch on an array value will no longer ` +
- `trigger on array mutation unless the "deep" option is specified. ` +
- `If current usage is intended, you can disable the compat behavior and ` +
- `suppress this warning with:` +
+ `Using keyCode as v-on modifier is no longer supported. ` +
+ `Use kebab-case key name modifiers instead.`,
+ link: `https://v3.vuejs.org/guide/migration/keycode-modifiers.html`
+ },
+
+ [DeprecationTypes.ATTR_FALSE_VALUE]: {
+ message: (name: string) =>
+ `Attribute "${name}" with v-bind value \`false\` will render ` +
+ `${name}="false" instead of removing it in Vue 3. To remove the attribute, ` +
+ `use \`null\` or \`undefined\` instead. If the usage is intended, ` +
+ `you can disable the compat behavior and suppress this warning with:` +
`\n\n configureCompat({ ${
- DeprecationTypes.WATCH_ARRAY
+ DeprecationTypes.ATTR_FALSE_VALUE
}: { enabled: false }})\n`,
- link: `https://v3.vuejs.org/guide/migration/watch.html`
+ link: `https://v3.vuejs.org/guide/migration/attribute-coercion.html`
+ },
+
+ [DeprecationTypes.ATTR_ENUMERATED_COERSION]: {
+ message: (name: string, value: any, coerced: string) =>
+ `Enumerated attribute "${name}" with v-bind value \`${value}\` will ` +
+ `${
+ value === null ? `be removed` : `render the value as-is`
+ } instead of coercing the value to "${coerced}" in Vue 3. ` +
+ `Always use explicit "true" or "false" values for enumerated attributes. ` +
+ `If the usage is intended, ` +
+ `you can disable the compat behavior and suppress this warning with:` +
+ `\n\n configureCompat({ ${
+ DeprecationTypes.ATTR_ENUMERATED_COERSION
+ }: { enabled: false }})\n`,
+ link: `https://v3.vuejs.org/guide/migration/attribute-coercion.html`
},
[DeprecationTypes.TRANSITION_CLASSES]: {
el.setAttributeNS(xlinkNS, key, value)
}
} else {
+ if (__COMPAT__ && compatCoerceAttr(el, key, value)) {
+ return
+ }
+
// note we are only checking boolean attributes that don't have a
// corresponding dom prop of the same name here.
const isBoolean = isSpecialBooleanAttr(key)
}
}
}
+
+// 2.x compat
+import { makeMap, NOOP } from '@vue/shared'
+import { compatUtils, DeprecationTypes } from '@vue/runtime-core'
+
+const isEnumeratedAttr = __COMPAT__
+ ? /*#__PURE__*/ makeMap('contenteditable,draggable,spellcheck')
+ : NOOP
+
+export function compatCoerceAttr(
+ el: Element,
+ key: string,
+ value: unknown
+): boolean {
+ if (isEnumeratedAttr(key)) {
+ const v2CocercedValue =
+ value === null
+ ? 'false'
+ : typeof value !== 'boolean' && value !== undefined
+ ? 'true'
+ : null
+ if (
+ v2CocercedValue &&
+ compatUtils.softAssertCompatEnabled(
+ DeprecationTypes.ATTR_ENUMERATED_COERSION,
+ key,
+ value,
+ v2CocercedValue
+ )
+ ) {
+ el.setAttribute(key, v2CocercedValue)
+ return true
+ }
+ } else if (
+ value === false &&
+ !isSpecialBooleanAttr(key) &&
+ compatUtils.softAssertCompatEnabled(DeprecationTypes.ATTR_FALSE_VALUE, key)
+ ) {
+ el.removeAttribute(key)
+ return true
+ }
+ return false
+}