@@ -16,7 +16,7 @@ import {
16
16
SUBMIT_BUTTON_LABEL ,
17
17
SUCCESS_MESSAGE_TEXT ,
18
18
} from './constants' ;
19
- import type { FeedbackInternalOptions , OptionalFeedbackConfiguration , Widget } from './types' ;
19
+ import type { FeedbackInternalOptions , FeedbackWidget , OptionalFeedbackConfiguration } from './types' ;
20
20
import { mergeOptions } from './util/mergeOptions' ;
21
21
import { createActorStyles } from './widget/Actor.css' ;
22
22
import { createShadowHost } from './widget/createShadowHost' ;
@@ -48,12 +48,12 @@ export class Feedback implements Integration {
48
48
/**
49
49
* Reference to widget element that is created when autoInject is true
50
50
*/
51
- private _widget : Widget | null ;
51
+ private _widget : FeedbackWidget | null ;
52
52
53
53
/**
54
54
* List of all widgets that are created from the integration
55
55
*/
56
- private _widgets : Set < Widget > ;
56
+ private _widgets : Set < FeedbackWidget > ;
57
57
58
58
/**
59
59
* Reference to the host element where widget is inserted
@@ -166,15 +166,7 @@ export class Feedback implements Integration {
166
166
}
167
167
168
168
try {
169
- // TODO: This is only here for hot reloading
170
- if ( this . _host ) {
171
- this . remove ( ) ;
172
- }
173
- const existingFeedback = doc . querySelector ( `#${ this . options . id } ` ) ;
174
- if ( existingFeedback ) {
175
- existingFeedback . remove ( ) ;
176
- }
177
- // TODO: End hotloading
169
+ this . _cleanupWidgetIfExists ( ) ;
178
170
179
171
const { autoInject } = this . options ;
180
172
@@ -183,20 +175,49 @@ export class Feedback implements Integration {
183
175
return ;
184
176
}
185
177
186
- this . _widget = this . _createWidget ( this . options ) ;
178
+ this . _createWidget ( this . options ) ;
187
179
} catch ( err ) {
188
180
__DEBUG_BUILD__ && logger . error ( err ) ;
189
181
}
190
182
}
191
183
184
+ /**
185
+ * Allows user to open the dialog box. Creates a new widget if
186
+ * `autoInject` was false, otherwise re-uses the default widget that was
187
+ * created during initialization of the integration.
188
+ */
189
+ public openDialog ( ) : void {
190
+ if ( ! this . _widget ) {
191
+ this . _createWidget ( { ...this . options , shouldCreateActor : false } ) ;
192
+ }
193
+
194
+ if ( ! this . _widget ) {
195
+ return ;
196
+ }
197
+
198
+ this . _widget . openDialog ( ) ;
199
+ }
200
+
201
+ /**
202
+ * Closes the dialog for the default widget, if it exists
203
+ */
204
+ public closeDialog ( ) : void {
205
+ if ( ! this . _widget ) {
206
+ // Nothing to do if widget does not exist
207
+ return ;
208
+ }
209
+
210
+ this . _widget . closeDialog ( ) ;
211
+ }
212
+
192
213
/**
193
214
* Adds click listener to attached element to open a feedback dialog
194
215
*/
195
- public attachTo ( el : Element | string , optionOverrides : OptionalFeedbackConfiguration ) : Widget | null {
216
+ public attachTo ( el : Element | string , optionOverrides ? : OptionalFeedbackConfiguration ) : FeedbackWidget | null {
196
217
try {
197
- const options = mergeOptions ( this . options , optionOverrides ) ;
218
+ const options = mergeOptions ( this . options , optionOverrides || { } ) ;
198
219
199
- return this . _ensureShadowHost < Widget | null > ( options , ( { shadow } ) => {
220
+ return this . _ensureShadowHost < FeedbackWidget | null > ( options , ( { shadow } ) => {
200
221
const targetEl =
201
222
typeof el === 'string' ? doc . querySelector ( el ) : typeof el . addEventListener === 'function' ? el : null ;
202
223
@@ -207,6 +228,11 @@ export class Feedback implements Integration {
207
228
208
229
const widget = createWidget ( { shadow, options, attachTo : targetEl } ) ;
209
230
this . _widgets . add ( widget ) ;
231
+
232
+ if ( ! this . _widget ) {
233
+ this . _widget = widget ;
234
+ }
235
+
210
236
return widget ;
211
237
} ) ;
212
238
} catch ( err ) {
@@ -218,9 +244,11 @@ export class Feedback implements Integration {
218
244
/**
219
245
* Creates a new widget. Accepts partial options to override any options passed to constructor.
220
246
*/
221
- public createWidget ( optionOverrides : OptionalFeedbackConfiguration ) : Widget | null {
247
+ public createWidget (
248
+ optionOverrides ?: OptionalFeedbackConfiguration & { shouldCreateActor ?: boolean } ,
249
+ ) : FeedbackWidget | null {
222
250
try {
223
- return this . _createWidget ( mergeOptions ( this . options , optionOverrides ) ) ;
251
+ return this . _createWidget ( mergeOptions ( this . options , optionOverrides || { } ) ) ;
224
252
} catch ( err ) {
225
253
__DEBUG_BUILD__ && logger . error ( err ) ;
226
254
return null ;
@@ -230,7 +258,7 @@ export class Feedback implements Integration {
230
258
/**
231
259
* Removes a single widget
232
260
*/
233
- public removeWidget ( widget : Widget | null | undefined ) : boolean {
261
+ public removeWidget ( widget : FeedbackWidget | null | undefined ) : boolean {
234
262
if ( ! widget ) {
235
263
return false ;
236
264
}
@@ -240,6 +268,12 @@ export class Feedback implements Integration {
240
268
widget . removeActor ( ) ;
241
269
widget . removeDialog ( ) ;
242
270
this . _widgets . delete ( widget ) ;
271
+
272
+ if ( this . _widget === widget ) {
273
+ // TODO: is more clean-up needed? e.g. call remove()
274
+ this . _widget = null ;
275
+ }
276
+
243
277
return true ;
244
278
}
245
279
} catch ( err ) {
@@ -249,6 +283,13 @@ export class Feedback implements Integration {
249
283
return false ;
250
284
}
251
285
286
+ /**
287
+ * Returns the default (first-created) widget
288
+ */
289
+ public getWidget ( ) : FeedbackWidget | null {
290
+ return this . _widget ;
291
+ }
292
+
252
293
/**
253
294
* Removes the Feedback integration (including host, shadow DOM, and all widgets)
254
295
*/
@@ -270,11 +311,25 @@ export class Feedback implements Integration {
270
311
this . _hasInsertedActorStyles = false ;
271
312
}
272
313
314
+ /**
315
+ * Clean-up the widget if it already exists in the DOM. This shouldn't happen
316
+ * in prod, but can happen in development with hot module reloading.
317
+ */
318
+ protected _cleanupWidgetIfExists ( ) : void {
319
+ if ( this . _host ) {
320
+ this . remove ( ) ;
321
+ }
322
+ const existingFeedback = doc . querySelector ( `#${ this . options . id } ` ) ;
323
+ if ( existingFeedback ) {
324
+ existingFeedback . remove ( ) ;
325
+ }
326
+ }
327
+
273
328
/**
274
329
* Creates a new widget, after ensuring shadow DOM exists
275
330
*/
276
- protected _createWidget ( options : FeedbackInternalOptions ) : Widget | null {
277
- return this . _ensureShadowHost < Widget > ( options , ( { shadow } ) => {
331
+ protected _createWidget ( options : FeedbackInternalOptions & { shouldCreateActor ?: boolean } ) : FeedbackWidget | null {
332
+ return this . _ensureShadowHost < FeedbackWidget > ( options , ( { shadow } ) => {
278
333
const widget = createWidget ( { shadow, options } ) ;
279
334
280
335
if ( ! this . _hasInsertedActorStyles && widget . actor ) {
@@ -283,6 +338,11 @@ export class Feedback implements Integration {
283
338
}
284
339
285
340
this . _widgets . add ( widget ) ;
341
+
342
+ if ( ! this . _widget ) {
343
+ this . _widget = widget ;
344
+ }
345
+
286
346
return widget ;
287
347
} ) ;
288
348
}
0 commit comments