@@ -16,7 +16,7 @@ import {
1616 SUBMIT_BUTTON_LABEL ,
1717 SUCCESS_MESSAGE_TEXT ,
1818} from './constants' ;
19- import type { FeedbackInternalOptions , OptionalFeedbackConfiguration , Widget } from './types' ;
19+ import type { FeedbackInternalOptions , FeedbackWidget , OptionalFeedbackConfiguration } from './types' ;
2020import { mergeOptions } from './util/mergeOptions' ;
2121import { createActorStyles } from './widget/Actor.css' ;
2222import { createShadowHost } from './widget/createShadowHost' ;
@@ -48,12 +48,12 @@ export class Feedback implements Integration {
4848 /**
4949 * Reference to widget element that is created when autoInject is true
5050 */
51- private _widget : Widget | null ;
51+ private _widget : FeedbackWidget | null ;
5252
5353 /**
5454 * List of all widgets that are created from the integration
5555 */
56- private _widgets : Set < Widget > ;
56+ private _widgets : Set < FeedbackWidget > ;
5757
5858 /**
5959 * Reference to the host element where widget is inserted
@@ -166,15 +166,7 @@ export class Feedback implements Integration {
166166 }
167167
168168 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 ( ) ;
178170
179171 const { autoInject } = this . options ;
180172
@@ -183,20 +175,49 @@ export class Feedback implements Integration {
183175 return ;
184176 }
185177
186- this . _widget = this . _createWidget ( this . options ) ;
178+ this . _createWidget ( this . options ) ;
187179 } catch ( err ) {
188180 __DEBUG_BUILD__ && logger . error ( err ) ;
189181 }
190182 }
191183
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+
192213 /**
193214 * Adds click listener to attached element to open a feedback dialog
194215 */
195- public attachTo ( el : Element | string , optionOverrides : OptionalFeedbackConfiguration ) : Widget | null {
216+ public attachTo ( el : Element | string , optionOverrides ? : OptionalFeedbackConfiguration ) : FeedbackWidget | null {
196217 try {
197- const options = mergeOptions ( this . options , optionOverrides ) ;
218+ const options = mergeOptions ( this . options , optionOverrides || { } ) ;
198219
199- return this . _ensureShadowHost < Widget | null > ( options , ( { shadow } ) => {
220+ return this . _ensureShadowHost < FeedbackWidget | null > ( options , ( { shadow } ) => {
200221 const targetEl =
201222 typeof el === 'string' ? doc . querySelector ( el ) : typeof el . addEventListener === 'function' ? el : null ;
202223
@@ -207,6 +228,11 @@ export class Feedback implements Integration {
207228
208229 const widget = createWidget ( { shadow, options, attachTo : targetEl } ) ;
209230 this . _widgets . add ( widget ) ;
231+
232+ if ( ! this . _widget ) {
233+ this . _widget = widget ;
234+ }
235+
210236 return widget ;
211237 } ) ;
212238 } catch ( err ) {
@@ -218,9 +244,11 @@ export class Feedback implements Integration {
218244 /**
219245 * Creates a new widget. Accepts partial options to override any options passed to constructor.
220246 */
221- public createWidget ( optionOverrides : OptionalFeedbackConfiguration ) : Widget | null {
247+ public createWidget (
248+ optionOverrides ?: OptionalFeedbackConfiguration & { shouldCreateActor ?: boolean } ,
249+ ) : FeedbackWidget | null {
222250 try {
223- return this . _createWidget ( mergeOptions ( this . options , optionOverrides ) ) ;
251+ return this . _createWidget ( mergeOptions ( this . options , optionOverrides || { } ) ) ;
224252 } catch ( err ) {
225253 __DEBUG_BUILD__ && logger . error ( err ) ;
226254 return null ;
@@ -230,7 +258,7 @@ export class Feedback implements Integration {
230258 /**
231259 * Removes a single widget
232260 */
233- public removeWidget ( widget : Widget | null | undefined ) : boolean {
261+ public removeWidget ( widget : FeedbackWidget | null | undefined ) : boolean {
234262 if ( ! widget ) {
235263 return false ;
236264 }
@@ -240,6 +268,12 @@ export class Feedback implements Integration {
240268 widget . removeActor ( ) ;
241269 widget . removeDialog ( ) ;
242270 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+
243277 return true ;
244278 }
245279 } catch ( err ) {
@@ -249,6 +283,13 @@ export class Feedback implements Integration {
249283 return false ;
250284 }
251285
286+ /**
287+ * Returns the default (first-created) widget
288+ */
289+ public getWidget ( ) : FeedbackWidget | null {
290+ return this . _widget ;
291+ }
292+
252293 /**
253294 * Removes the Feedback integration (including host, shadow DOM, and all widgets)
254295 */
@@ -270,11 +311,25 @@ export class Feedback implements Integration {
270311 this . _hasInsertedActorStyles = false ;
271312 }
272313
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+
273328 /**
274329 * Creates a new widget, after ensuring shadow DOM exists
275330 */
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 } ) => {
278333 const widget = createWidget ( { shadow, options } ) ;
279334
280335 if ( ! this . _hasInsertedActorStyles && widget . actor ) {
@@ -283,6 +338,11 @@ export class Feedback implements Integration {
283338 }
284339
285340 this . _widgets . add ( widget ) ;
341+
342+ if ( ! this . _widget ) {
343+ this . _widget = widget ;
344+ }
345+
286346 return widget ;
287347 } ) ;
288348 }
0 commit comments