Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
91144a2
test: add tests for attribute fallthrough on functional component
edison1105 Nov 27, 2025
e654550
test: add more tests
edison1105 Nov 27, 2025
4223dac
test: warn when fallthrough fails on non-single-root
edison1105 Nov 27, 2025
c9f9b85
fix: prevent Teleport attrs fallthrough by ensuring its nodes are alw…
edison1105 Nov 27, 2025
087c10f
refactor(Teleport): extract inline mount and mountToTarget functions …
edison1105 Nov 28, 2025
02a013a
refactor: refine fallthrough attribute to single root elements across…
edison1105 Nov 28, 2025
a8c435d
refactor: relocate `getRootElement` to `custom.ts` and update custom …
edison1105 Nov 28, 2025
9d25c35
fix: warn extraneous attributes for non-single-root components and pr…
edison1105 Nov 28, 2025
c298156
fix: prevent extraneous attributes warning for empty component blocks.
edison1105 Nov 28, 2025
2206dba
docs: add comments explaining attribute fallthrough prevention for sl…
edison1105 Nov 28, 2025
624acc6
fix: Track `$attrs` access to suppress extraneous attribute warnings …
edison1105 Nov 28, 2025
624cb19
refactor: remove fallthrough props from Transition and TransitionGroup
edison1105 Nov 29, 2025
bfeb2d9
refactor: restrict Teleport extraneous attribute warning to dev mode.
edison1105 Nov 29, 2025
0fb2278
refactor: simplify fragment update logic by removing `isUpdate` varia…
edison1105 Nov 29, 2025
b603d83
Revert "refactor: relocate `getRootElement` to `custom.ts` and update…
edison1105 Nov 29, 2025
654687b
refactor: remove `filterSingleRootElement` and refine attribute fallt…
edison1105 Nov 29, 2025
1ae7da0
refactor: simplify TeleportFragment nodes to directly hold content in…
edison1105 Nov 29, 2025
d9b690f
refactor: manage fallthrough attributes for dynamic fragments using a…
edison1105 Nov 29, 2025
19bba81
refactor: remove special attribute fallthrough handling for functiona…
edison1105 Nov 29, 2025
36b47d1
feat: implement attribute fallthrough logic for functional components…
edison1105 Nov 29, 2025
e1626b3
fix: apply fragment fallthrough attributes reactively using `renderEf…
edison1105 Nov 29, 2025
ac22224
fix: prevent functional fallthrough props from being applied to Vapor…
edison1105 Nov 29, 2025
4438967
test: add more tests
edison1105 Nov 30, 2025
fa01278
test: add more tests
edison1105 Dec 1, 2025
59425b0
chore: revert teleport changes
edison1105 Dec 1, 2025
fb0485e
fix: improve handling of VaporTransition components and enhance fallt…
edison1105 Dec 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 42 additions & 35 deletions packages/runtime-core/src/componentRenderUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,40 +169,7 @@ export function renderComponentRoot(
}
root = cloneVNode(root, fallthroughAttrs, false, true)
} else if (__DEV__ && !accessedAttrs && root.type !== Comment) {
const allAttrs = Object.keys(attrs)
const eventAttrs: string[] = []
const extraAttrs: string[] = []
for (let i = 0, l = allAttrs.length; i < l; i++) {
const key = allAttrs[i]
if (isOn(key)) {
// ignore v-model handlers when they fail to fallthrough
if (!isModelListener(key)) {
// remove `on`, lowercase first letter to reflect event casing
// accurately
eventAttrs.push(key[2].toLowerCase() + key.slice(3))
}
} else {
extraAttrs.push(key)
}
}
if (extraAttrs.length) {
warn(
`Extraneous non-props attributes (` +
`${extraAttrs.join(', ')}) ` +
`were passed to component but could not be automatically inherited ` +
`because component renders fragment or text or teleport root nodes.`,
)
}
if (eventAttrs.length) {
warn(
`Extraneous non-emits event listeners (` +
`${eventAttrs.join(', ')}) ` +
`were passed to component but could not be automatically inherited ` +
`because component renders fragment or text root nodes. ` +
`If the listener is intended to be a component custom event listener only, ` +
`declare it using the "emits" option.`,
)
}
warnExtraneousAttributes(attrs)
}
}
}
Expand Down Expand Up @@ -302,6 +269,46 @@ const getChildRoot = (vnode: VNode): [VNode, SetRootFn] => {
return [normalizeVNode(childRoot), setRoot]
}

/**
* Dev only
*/
export function warnExtraneousAttributes(attrs: Record<string, any>): void {
const allAttrs = Object.keys(attrs)
const eventAttrs: string[] = []
const extraAttrs: string[] = []
for (let i = 0, l = allAttrs.length; i < l; i++) {
const key = allAttrs[i]
if (isOn(key)) {
// ignore v-model handlers when they fail to fallthrough
if (!isModelListener(key)) {
// remove `on`, lowercase first letter to reflect event casing
// accurately
eventAttrs.push(key[2].toLowerCase() + key.slice(3))
}
} else {
extraAttrs.push(key)
}
}
if (extraAttrs.length) {
warn(
`Extraneous non-props attributes (` +
`${extraAttrs.join(', ')}) ` +
`were passed to component but could not be automatically inherited ` +
`because component renders fragment or text or teleport root nodes.`,
)
}
if (eventAttrs.length) {
warn(
`Extraneous non-emits event listeners (` +
`${eventAttrs.join(', ')}) ` +
`were passed to component but could not be automatically inherited ` +
`because component renders fragment or text root nodes. ` +
`If the listener is intended to be a component custom event listener only, ` +
`declare it using the "emits" option.`,
)
}
}

export function filterSingleRoot(
children: VNodeArrayChildren,
recurse = true,
Expand Down Expand Up @@ -334,7 +341,7 @@ export function filterSingleRoot(
return singleRoot
}

const getFunctionalFallthrough = (attrs: Data): Data | undefined => {
export const getFunctionalFallthrough = (attrs: Data): Data | undefined => {
let res: Data | undefined
for (const key in attrs) {
if (key === 'class' || key === 'style' || isOn(key)) {
Expand Down
8 changes: 8 additions & 0 deletions packages/runtime-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,3 +674,11 @@ export {
* @internal
*/
export type { GenericComponent } from './component'

/**
* @internal
*/
export {
warnExtraneousAttributes,
getFunctionalFallthrough,
} from './componentRenderUtils'
Loading
Loading