--- /dev/null
+import { isOn } from '@vue/shared'
+import { ComponentInternalInstance } from '../component'
+import { DeprecationTypes, isCompatEnabled } from './compatConfig'
+
+export function shouldSkipAttr(
+ key: string,
+ instance: ComponentInternalInstance
+): boolean {
+ if (
+ (key === 'class' || key === 'style') &&
+ isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance)
+ ) {
+ return true
+ }
+ if (
+ isOn(key) &&
+ isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance)
+ ) {
+ return true
+ }
+ return false
+}
},
[DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE]: {
- message:
- `vm.$attrs now includes class and style bindings passed from parent. ` +
- `Components with inheritAttrs: false will no longer auto-inherit ` +
- `class/style on its root element. If your code relies on this behavior, ` +
- `you may see broken styling and need to adjust your CSS. Otherwise, ` +
- `you can disable the compat behavior and suppress this warning with:` +
- `\n\n configureCompat({ ${
- DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE
- }: false )\n`,
+ message: componentName =>
+ `Component <${componentName}> has \`inheritAttrs: false\` but is ` +
+ `relying on class/style fallthrough from parent. In Vue 3, class/style ` +
+ `are now included in $attrs and will no longer fallthrough when ` +
+ `inheritAttrs is false. If you are already using v-bind="$attrs" on ` +
+ `component root it should render the same end result. ` +
+ `If you are binding $attrs to a non-root element and expecting ` +
+ `class/style to fallthrough on root, you will need to now manually bind ` +
+ `them on root via :class="$attrs.class".`,
link: `https://v3.vuejs.org/guide/migration/attrs-includes-class-style.html`
},
import {
DeprecationTypes,
assertCompatEnabled,
- checkCompatEnabled,
isCompatEnabled
} from './compatConfig'
import { off, on, once } from './instanceEventEmitter'
return __DEV__ ? shallowReadonly(i.slots) : i.slots
},
- // overrides existing accessor
- $attrs: i => {
- if (__DEV__ && i.type.inheritAttrs === false) {
- checkCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, i)
- }
- return __DEV__ ? shallowReadonly(i.attrs) : i.attrs
- },
-
$on: i => on.bind(null, i),
$once: i => once.bind(null, i),
$off: i => off.bind(null, i),
isReservedProp,
EMPTY_ARR,
def,
- extend,
- isOn
+ extend
} from '@vue/shared'
import { warn } from './warning'
import {
import { createPropsDefaultThis } from './compat/props'
import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
import { DeprecationTypes } from './compat/compatConfig'
+import { shouldSkipAttr } from './compat/attrsFallthrough'
export type ComponentPropsOptions<P = Data> =
| ComponentObjectPropsOptions<P>
)
}
} else {
- if (
- __COMPAT__ &&
- isOn(key) &&
- isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance)
- ) {
+ if (__COMPAT__ && shouldSkipAttr(key, instance)) {
continue
}
if (value !== attrs[key]) {
// Any non-declared (either as a prop or an emitted event) props are put
// into a separate `attrs` object for spreading. Make sure to preserve
// original key casing
- if (
- __COMPAT__ &&
- isOn(key) &&
- isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance)
- ) {
+ if (__COMPAT__ && shouldSkipAttr(key, instance)) {
continue
}
if (value !== attrs[key]) {
import {
ComponentInternalInstance,
FunctionalComponent,
- Data
+ Data,
+ getComponentName
} from './component'
import {
VNode,
import { NormalizedProps } from './componentProps'
import { isEmitListener } from './componentEmits'
import { setCurrentRenderingInstance } from './componentRenderContext'
+import {
+ DeprecationTypes,
+ isCompatEnabled,
+ warnDeprecation
+} from './compat/compatConfig'
/**
* dev only flag to track whether $attrs was used during render.
;[root, setRoot] = getChildRoot(result)
}
- if (Component.inheritAttrs !== false && fallthroughAttrs) {
+ if (fallthroughAttrs && Component.inheritAttrs !== false) {
const keys = Object.keys(fallthroughAttrs)
const { shapeFlag } = root
if (keys.length) {
}
}
+ if (
+ __COMPAT__ &&
+ isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance) &&
+ vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT &&
+ (root.shapeFlag & ShapeFlags.ELEMENT ||
+ root.shapeFlag & ShapeFlags.COMPONENT)
+ ) {
+ const { class: cls, style } = vnode.props || {}
+ if (cls || style) {
+ if (__DEV__ && Component.inheritAttrs === false) {
+ warnDeprecation(
+ DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE,
+ instance,
+ getComponentName(instance.type)
+ )
+ }
+ root = cloneVNode(root, {
+ class: cls,
+ style: style
+ })
+ }
+ }
+
// inherit directives
if (vnode.dirs) {
if (__DEV__ && !isElementRoot(root)) {