@@ -20,7 +20,7 @@ import {
20
20
nextTick ,
21
21
warn
22
22
} from '@vue/runtime-core'
23
- import { camelize , hyphenate , isArray } from '@vue/shared'
23
+ import { camelize , extend , hyphenate , isArray , toNumber } from '@vue/shared'
24
24
import { hydrate , render } from '.'
25
25
26
26
type VueElementConstructor < P = { } > = {
@@ -134,7 +134,7 @@ export function defineCustomElement(
134
134
return attrKeys
135
135
}
136
136
constructor ( ) {
137
- super ( Comp , attrKeys , hydate )
137
+ super ( Comp , attrKeys , propKeys , hydate )
138
138
}
139
139
}
140
140
@@ -173,12 +173,13 @@ export class VueElement extends HTMLElement {
173
173
174
174
constructor (
175
175
private _def : Component ,
176
- private _attrs : string [ ] ,
176
+ private _attrKeys : string [ ] ,
177
+ private _propKeys : string [ ] ,
177
178
hydrate ?: RootHydrateFunction
178
179
) {
179
180
super ( )
180
181
if ( this . shadowRoot && hydrate ) {
181
- hydrate ( this . _initVNode ( ) , this . shadowRoot )
182
+ hydrate ( this . _createVNode ( ) , this . shadowRoot )
182
183
} else {
183
184
if ( __DEV__ && this . shadowRoot ) {
184
185
warn (
@@ -191,15 +192,23 @@ export class VueElement extends HTMLElement {
191
192
}
192
193
193
194
attributeChangedCallback ( name : string , _oldValue : string , newValue : string ) {
194
- if ( this . _attrs . includes ( name ) ) {
195
- this . _setProp ( camelize ( name ) , newValue )
195
+ if ( this . _attrKeys . includes ( name ) ) {
196
+ this . _setProp ( camelize ( name ) , toNumber ( newValue ) , false )
196
197
}
197
198
}
198
199
199
200
connectedCallback ( ) {
200
201
this . _connected = true
201
202
if ( ! this . _instance ) {
202
- render ( this . _initVNode ( ) , this . shadowRoot ! )
203
+ // check if there are props set pre-upgrade
204
+ for ( const key of this . _propKeys ) {
205
+ if ( this . hasOwnProperty ( key ) ) {
206
+ const value = ( this as any ) [ key ]
207
+ delete ( this as any ) [ key ]
208
+ this . _setProp ( key , value )
209
+ }
210
+ }
211
+ render ( this . _createVNode ( ) , this . shadowRoot ! )
203
212
}
204
213
}
205
214
@@ -213,41 +222,61 @@ export class VueElement extends HTMLElement {
213
222
} )
214
223
}
215
224
225
+ /**
226
+ * @internal
227
+ */
216
228
protected _getProp ( key : string ) {
217
229
return this . _props [ key ]
218
230
}
219
231
220
- protected _setProp ( key : string , val : any ) {
221
- const oldValue = this . _props [ key ]
222
- this . _props [ key ] = val
223
- if ( this . _instance && val !== oldValue ) {
224
- this . _instance . props [ key ] = val
232
+ /**
233
+ * @internal
234
+ */
235
+ protected _setProp ( key : string , val : any , shouldReflect = true ) {
236
+ if ( val !== this . _props [ key ] ) {
237
+ this . _props [ key ] = val
238
+ if ( this . _instance ) {
239
+ render ( this . _createVNode ( ) , this . shadowRoot ! )
240
+ }
241
+ // reflect
242
+ if ( shouldReflect ) {
243
+ if ( val === true ) {
244
+ this . setAttribute ( hyphenate ( key ) , '' )
245
+ } else if ( typeof val === 'string' || typeof val === 'number' ) {
246
+ this . setAttribute ( hyphenate ( key ) , val + '' )
247
+ } else if ( ! val ) {
248
+ this . removeAttribute ( hyphenate ( key ) )
249
+ }
250
+ }
225
251
}
226
252
}
227
253
228
- protected _initVNode ( ) : VNode < any , any > {
229
- const vnode = createVNode ( this . _def , this . _props )
230
- vnode . ce = instance => {
231
- this . _instance = instance
232
- instance . isCE = true
254
+ private _createVNode ( ) : VNode < any , any > {
255
+ const vnode = createVNode ( this . _def , extend ( { } , this . _props ) )
256
+ if ( ! this . _instance ) {
257
+ vnode . ce = instance => {
258
+ this . _instance = instance
259
+ instance . isCE = true
233
260
234
- // intercept emit
235
- instance . emit = ( event : string , ...args : any [ ] ) => {
236
- this . dispatchEvent (
237
- new CustomEvent ( event , {
238
- detail : args
239
- } )
240
- )
241
- }
261
+ // intercept emit
262
+ instance . emit = ( event : string , ...args : any [ ] ) => {
263
+ this . dispatchEvent (
264
+ new CustomEvent ( event , {
265
+ detail : args
266
+ } )
267
+ )
268
+ }
242
269
243
- // locate nearest Vue custom element parent for provide/inject
244
- let parent : Node | null = this
245
- while (
246
- ( parent = parent && ( parent . parentNode || ( parent as ShadowRoot ) . host ) )
247
- ) {
248
- if ( parent instanceof VueElement ) {
249
- instance . parent = parent . _instance
250
- break
270
+ // locate nearest Vue custom element parent for provide/inject
271
+ let parent : Node | null = this
272
+ while (
273
+ ( parent =
274
+ parent && ( parent . parentNode || ( parent as ShadowRoot ) . host ) )
275
+ ) {
276
+ if ( parent instanceof VueElement ) {
277
+ instance . parent = parent . _instance
278
+ break
279
+ }
251
280
}
252
281
}
253
282
}
0 commit comments