44 */
55
66import { createPinia } from 'pinia'
7- import { createApp } from 'vue'
7+ import { createApp , type App as VueApp } from 'vue'
88
99import { loadState } from '@nextcloud/initial-state'
1010import { t , n } from '@nextcloud/l10n'
1111import { FileType , registerSidebarTab } from '@nextcloud/files'
1212
1313import LibreSignLogoDarkSvg from '../img/app-dark.svg?raw'
1414
15- import AppFilesTab from './components/RightSidebar/AppFilesTab.vue'
16-
1715import './style/icons.scss'
1816
1917if ( ! window . OCA . Libresign ) {
@@ -79,11 +77,13 @@ function mapNodeToFileInfo(node: SidebarNode = {}): FileInfo {
7977interface LibreSignSidebarTabElement extends HTMLElement {
8078 _node ?: SidebarNode
8179 _active ?: boolean
80+ _vueApp ?: VueApp < Element > | null
8281 _vueInstance ?: TabComponentInstance | null
82+ _mountPromise ?: Promise < void > | null
8383 node ?: SidebarNode
8484 update ( fileInfo : FileInfo ) : void
8585 setActive ( active : boolean ) : Promise < void >
86- mountVue ( ) : void
86+ mountVue ( ) : Promise < void >
8787 destroyVue ( ) : void
8888 updateFromNode ( ) : void
8989}
@@ -98,11 +98,12 @@ function setupCustomElement() {
9898 class LibreSignSidebarTab extends HTMLElement implements LibreSignSidebarTabElement {
9999 _node ?: SidebarNode
100100 _active ?: boolean
101+ _vueApp ?: VueApp < Element > | null
101102 _vueInstance ?: TabComponentInstance | null
103+ _mountPromise ?: Promise < void > | null
102104
103105 connectedCallback ( ) {
104- this . mountVue ( )
105- this . updateFromNode ( )
106+ void this . mountVue ( )
106107 }
107108
108109 disconnectedCallback ( ) {
@@ -132,35 +133,45 @@ function setupCustomElement() {
132133 }
133134 }
134135
135- mountVue ( ) {
136- if ( this . _vueInstance ) {
137- return
136+ async mountVue ( ) {
137+ if ( this . _vueInstance || this . _mountPromise ) {
138+ return this . _mountPromise ?? Promise . resolve ( )
138139 }
139140
140- const app = createApp ( AppFilesTab )
141- app . config . globalProperties . t = t
142- app . config . globalProperties . n = n
143- app . use ( pinia )
141+ this . _mountPromise = ( async ( ) => {
142+ const { default : AppFilesTab } = await import ( './components/RightSidebar/AppFilesTab.vue' )
143+ if ( ! this . isConnected || this . _vueInstance ) {
144+ return
145+ }
146+
147+ const app = createApp ( AppFilesTab )
148+ app . config . globalProperties . t = t
149+ app . config . globalProperties . n = n
150+ app . use ( pinia )
151+
152+ const element = document . createElement ( 'div' )
153+ this . _vueApp = app
154+ this . _vueInstance = app . mount ( element )
155+ this . appendChild ( element )
156+ this . updateFromNode ( )
157+ } ) ( ) . finally ( ( ) => {
158+ this . _mountPromise = null
159+ } )
144160
145- const element = document . createElement ( 'div' )
146- this . _vueInstance = app . mount ( element )
147- this . appendChild ( element )
161+ return this . _mountPromise
148162 }
149163
150164 destroyVue ( ) {
151- if ( this . _vueInstance && this . _vueInstance . $el ) {
152- // For Vue 3, we need to unmount the app
153- // The best way would be to track the app instance
154- this . _vueInstance = null
155- }
165+ this . _vueApp ?. unmount ( )
166+ this . _vueApp = null
167+ this . _vueInstance = null
156168 }
157169
158170 updateFromNode ( ) {
159171 if ( ! this . _vueInstance || ! this . _node ) {
160172 return
161173 }
162174 const fileInfo = mapNodeToFileInfo ( this . _node )
163- // Call update on the mounted component if it exists
164175 if ( typeof this . _vueInstance . update === 'function' ) {
165176 this . _vueInstance . update ( fileInfo )
166177 }
0 commit comments