@@ -20,7 +20,7 @@ import {
2020 nextTick ,
2121 warn
2222} from '@vue/runtime-core'
23- import { camelize , hyphenate , isArray } from '@vue/shared'
23+ import { camelize , extend , hyphenate , isArray , toNumber } from '@vue/shared'
2424import { hydrate , render } from '.'
2525
2626type VueElementConstructor < P = { } > = {
@@ -134,7 +134,7 @@ export function defineCustomElement(
134134 return attrKeys
135135 }
136136 constructor ( ) {
137- super ( Comp , attrKeys , hydate )
137+ super ( Comp , attrKeys , propKeys , hydate )
138138 }
139139 }
140140
@@ -173,12 +173,13 @@ export class VueElement extends HTMLElement {
173173
174174 constructor (
175175 private _def : Component ,
176- private _attrs : string [ ] ,
176+ private _attrKeys : string [ ] ,
177+ private _propKeys : string [ ] ,
177178 hydrate ?: RootHydrateFunction
178179 ) {
179180 super ( )
180181 if ( this . shadowRoot && hydrate ) {
181- hydrate ( this . _initVNode ( ) , this . shadowRoot )
182+ hydrate ( this . _createVNode ( ) , this . shadowRoot )
182183 } else {
183184 if ( __DEV__ && this . shadowRoot ) {
184185 warn (
@@ -191,15 +192,23 @@ export class VueElement extends HTMLElement {
191192 }
192193
193194 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 )
196197 }
197198 }
198199
199200 connectedCallback ( ) {
200201 this . _connected = true
201202 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 ! )
203212 }
204213 }
205214
@@ -213,41 +222,61 @@ export class VueElement extends HTMLElement {
213222 } )
214223 }
215224
225+ /**
226+ * @internal
227+ */
216228 protected _getProp ( key : string ) {
217229 return this . _props [ key ]
218230 }
219231
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+ }
225251 }
226252 }
227253
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
233260
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+ }
242269
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+ }
251280 }
252281 }
253282 }
0 commit comments