Skip to content

Commit 19bba81

Browse files
committed
refactor: remove special attribute fallthrough handling for functional components.
1 parent d9b690f commit 19bba81

File tree

5 files changed

+86
-108
lines changed

5 files changed

+86
-108
lines changed

packages/runtime-vapor/__tests__/componentAttrs.spec.ts

Lines changed: 80 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -66,64 +66,67 @@ describe('attribute fallthrough', () => {
6666
expect(host.innerHTML).toBe('<div id="b">2</div>')
6767
})
6868

69-
it('should only allow whitelisted fallthrough on functional component with optional props', async () => {
70-
const click = vi.fn()
71-
const childUpdated = vi.fn()
72-
73-
const count = ref(0)
74-
75-
function inc() {
76-
count.value++
77-
click()
78-
}
79-
80-
const Hello = () =>
81-
createComponent(Child, {
82-
foo: () => count.value + 1,
83-
id: () => 'test',
84-
class: () => 'c' + count.value,
85-
style: () => ({
86-
color: count.value ? 'red' : 'green',
87-
}),
88-
onClick: () => inc,
89-
})
90-
91-
const Child = defineVaporComponent((props: any) => {
92-
childUpdated()
93-
const n0 = template(
94-
'<div class="c2" style="font-weight: bold"></div>',
95-
true,
96-
)() as Element
97-
renderEffect(() => setElementText(n0, props.foo))
98-
return n0
99-
})
69+
it.todo(
70+
'should only allow whitelisted fallthrough on functional component with optional props',
71+
async () => {
72+
const click = vi.fn()
73+
const childUpdated = vi.fn()
10074

101-
const { host: root } = define(Hello).render()
102-
expect(root.innerHTML).toBe(
103-
'<div class="c2 c0" style="font-weight: bold; color: green;"></div>',
104-
)
75+
const count = ref(0)
10576

106-
const node = root.children[0] as HTMLElement
77+
function inc() {
78+
count.value++
79+
click()
80+
}
10781

108-
// not whitelisted
109-
expect(node.getAttribute('id')).toBe(null)
110-
expect(node.getAttribute('foo')).toBe(null)
82+
const Hello = () =>
83+
createComponent(Child, {
84+
foo: () => count.value + 1,
85+
id: () => 'test',
86+
class: () => 'c' + count.value,
87+
style: () => ({
88+
color: count.value ? 'red' : 'green',
89+
}),
90+
onClick: () => inc,
91+
})
11192

112-
// whitelisted: style, class, event listeners
113-
expect(node.getAttribute('class')).toBe('c2 c0')
114-
expect(node.style.color).toBe('green')
115-
expect(node.style.fontWeight).toBe('bold')
116-
node.dispatchEvent(new CustomEvent('click'))
117-
expect(click).toHaveBeenCalled()
93+
const { component: Child } = define((props: any) => {
94+
childUpdated()
95+
const n0 = template(
96+
'<div class="c2" style="font-weight: bold"></div>',
97+
true,
98+
)() as Element
99+
renderEffect(() => setElementText(n0, props.foo))
100+
return n0
101+
})
118102

119-
await nextTick()
120-
expect(childUpdated).toHaveBeenCalled()
121-
expect(node.getAttribute('id')).toBe(null)
122-
expect(node.getAttribute('foo')).toBe(null)
123-
expect(node.getAttribute('class')).toBe('c2 c1')
124-
expect(node.style.color).toBe('red')
125-
expect(node.style.fontWeight).toBe('bold')
126-
})
103+
const { host: root } = define(Hello).render()
104+
expect(root.innerHTML).toBe(
105+
'<div class="c2 c0" style="font-weight: bold; color: green;">1</div>',
106+
)
107+
108+
const node = root.children[0] as HTMLElement
109+
110+
// not whitelisted
111+
expect(node.getAttribute('id')).toBe(null)
112+
expect(node.getAttribute('foo')).toBe(null)
113+
114+
// whitelisted: style, class, event listeners
115+
expect(node.getAttribute('class')).toBe('c2 c0')
116+
expect(node.style.color).toBe('green')
117+
expect(node.style.fontWeight).toBe('bold')
118+
node.dispatchEvent(new CustomEvent('click'))
119+
expect(click).toHaveBeenCalled()
120+
121+
await nextTick()
122+
expect(childUpdated).toHaveBeenCalled()
123+
expect(node.getAttribute('id')).toBe(null)
124+
expect(node.getAttribute('foo')).toBe(null)
125+
expect(node.getAttribute('class')).toBe('c2 c1')
126+
expect(node.style.color).toBe('red')
127+
expect(node.style.fontWeight).toBe('bold')
128+
},
129+
)
127130

128131
it('should allow all attrs on functional component with declared props', async () => {
129132
const click = vi.fn()
@@ -453,37 +456,34 @@ describe('attribute fallthrough', () => {
453456
expect(html()).toBe(`<div></div><div class="parent"></div>`)
454457
})
455458

456-
it.todo(
457-
'should not warn when functional component has optional props',
458-
() => {
459-
const Parent = {
460-
render() {
461-
return createComponent(Child, {
462-
foo: () => 1,
463-
class: () => 'parent',
464-
onBar: () => () => {},
465-
})
466-
},
467-
}
468-
469-
const Child = defineVaporComponent((props: any) => {
470-
const n0 = template('<div></div>')() as Element
471-
const n1 = template('<div></div>')() as Element
472-
renderEffect(() => {
473-
setClass(n1, 'class', props.class)
459+
it('should not warn when functional component has optional props', () => {
460+
const Parent = {
461+
render() {
462+
return createComponent(Child, {
463+
foo: () => 1,
464+
class: () => 'parent',
465+
onBar: () => () => {},
474466
})
475-
return [n0, n1]
467+
},
468+
}
469+
470+
const { component: Child } = define((props: any) => {
471+
const n0 = template('<div></div>')() as Element
472+
const n1 = template('<div></div>')() as Element
473+
renderEffect(() => {
474+
setClass(n1, props.class)
476475
})
476+
return [n0, n1]
477+
})
477478

478-
const root = document.createElement('div')
479-
document.body.appendChild(root)
480-
const { html } = define(Parent).render()
479+
const root = document.createElement('div')
480+
document.body.appendChild(root)
481+
const { html } = define(Parent).render()
481482

482-
expect(`Extraneous non-props attributes`).not.toHaveBeenWarned()
483-
expect(`Extraneous non-emits event listeners`).not.toHaveBeenWarned()
484-
expect(html()).toBe(`<div></div><div class="parent"></div>`)
485-
},
486-
)
483+
expect(`Extraneous non-props attributes`).not.toHaveBeenWarned()
484+
expect(`Extraneous non-emits event listeners`).not.toHaveBeenWarned()
485+
expect(html()).toBe(`<div></div><div class="parent"></div>`)
486+
})
487487

488488
// it('should warn when functional component has props and does not use attrs', () => {
489489
// const Parent = {

packages/runtime-vapor/__tests__/componentProps.spec.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -139,24 +139,13 @@ describe('component: props', () => {
139139
}),
140140
)
141141

142-
const clickHandler = () => {}
143-
render({
144-
foo: () => 1,
145-
style: () => ({
146-
color: 'red',
147-
}),
148-
class: () => 'my-class',
149-
onClick: () => clickHandler,
150-
})
142+
render({ foo: () => 1 })
151143
expect(props).toEqual({})
144+
expect(attrs).toEqual({ foo: 1 })
152145

153-
// for functional components, only style/class/onX
154-
// are included in attrs
155-
expect(attrs).toEqual({
156-
style: [{ color: 'red' }],
157-
class: ['my-class'],
158-
onClick: clickHandler,
159-
})
146+
render({ bar: () => 2 })
147+
expect(props).toEqual({})
148+
expect(attrs).toEqual({ bar: 2 })
160149
})
161150

162151
test('boolean casting', () => {

packages/runtime-vapor/src/apiDefineComponent.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export function defineVaporComponent(
1313
extend({ name: comp.name }, extraOptions, {
1414
setup: comp,
1515
__vapor: true,
16-
__functional: true,
1716
}))()
1817
}
1918
// TODO type inference

packages/runtime-vapor/src/component.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,6 @@ interface SharedInternalOptions {
157157
* Cached normalized emits options.
158158
*/
159159
__emitsOptions?: ObjectEmitsOptions
160-
161-
/**
162-
* indicates functional vapor component
163-
*/
164-
__functional?: true
165160
}
166161

167162
// In TypeScript, it is actually impossible to have a record type with only

packages/runtime-vapor/src/componentProps.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
hasOwn,
77
isArray,
88
isFunction,
9-
isOn,
109
isString,
1110
} from '@vue/shared'
1211
import type { VaporComponent, VaporComponentInstance } from './component'
@@ -64,11 +63,7 @@ export function getPropsProxyHandlers(
6463
const isAttr = propsOptions
6564
? (key: string) =>
6665
key !== '$' && !isProp(key) && !isEmitListener(emitsOptions, key)
67-
: // treat class/style/onX as attrs for function components
68-
comp.__functional
69-
? (key: string | symbol) =>
70-
key === 'class' || key === 'style' || (isString(key) && isOn(key))
71-
: YES
66+
: YES
7267

7368
const getProp = (instance: VaporComponentInstance, key: string | symbol) => {
7469
// this enables direct watching of props and prevents `Invalid watch source` DEV warnings.

0 commit comments

Comments
 (0)