Socket
Socket
Sign inDemoInstall

@sentry-internal/feedback

Package Overview
Dependencies
Maintainers
9
Versions
121
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sentry-internal/feedback - npm Package Compare versions

Comparing version 0.0.1-alpha.9 to 0.0.1-alpha.10

build/npm/types-ts3.8/util/takeScreenshot.d.ts

180

build/npm/cjs/index.js

@@ -159,2 +159,3 @@ Object.defineProperty(exports, '__esModule', { value: true });

const INHERIT = 'inherit';
const SUBMIT_COLOR = 'rgba(108, 95, 199, 1)';
const LIGHT_THEME = {

@@ -174,5 +175,7 @@ fontFamily: "'Helvetica Neue', Arial, sans-serif",

submitBackground: 'rgba(88, 74, 192, 1)',
submitBackgroundHover: 'rgba(108, 95, 199, 1)',
submitBorder: 'rgba(108, 95, 199, 1)',
submitBackgroundHover: SUBMIT_COLOR,
submitBorder: SUBMIT_COLOR,
submitOutlineFocus: '#29232f',
submitForeground: LIGHT_BACKGROUND,
submitForegroundHover: LIGHT_BACKGROUND,

@@ -182,3 +185,5 @@ cancelBackground: 'transparent',

cancelBorder: 'var(--border)',
cancelOutlineFocus: 'var(--input-outline-focus)',
cancelForeground: 'var(--foreground)',
cancelForegroundHover: 'var(--foreground)',

@@ -188,3 +193,3 @@ inputBackground: INHERIT,

inputBorder: 'var(--border)',
inputBorderFocus: 'rgba(108, 95, 199, 1)',
inputOutlineFocus: SUBMIT_COLOR,
};

@@ -419,5 +424,4 @@

.form__input:focus {
outline: 1px solid transparent;
outline-color: var(--input-border-focus);
.form__input:focus-visible {
outline: 1px auto var(--input-outline-focus);
}

@@ -457,3 +461,7 @@

background-color: var(--submit-background-hover);
color: var(--submit-foreground-hover);
}
.btn--primary:focus-visible {
outline: 1px auto var(--submit-outline-focus);
}

@@ -467,3 +475,7 @@ .btn--default {

background-color: var(--cancel-background-hover);
color: var(--cancel-foreground-hover);
}
.btn--default:focus-visible {
outline: 1px auto var(--cancel-outline-focus);
}

@@ -507,3 +519,5 @@ .success-message {

--submit-border: ${theme.submitBorder};
--submit-outline-focus: ${theme.submitOutlineFocus};
--submit-foreground: ${theme.submitForeground};
--submit-foreground-hover: ${theme.submitForegroundHover};

@@ -513,3 +527,5 @@ --cancel-background: ${theme.cancelBackground};

--cancel-border: ${theme.cancelBorder};
--cancel-outline-focus: ${theme.cancelOutlineFocus};
--cancel-foreground: ${theme.cancelForeground};
--cancel-foreground-hover: ${theme.cancelForegroundHover};

@@ -519,3 +535,3 @@ --input-background: ${theme.inputBackground};

--input-border: ${theme.inputBorder};
--input-border-focus: ${theme.inputBorderFocus};
--input-outline-focus: ${theme.inputOutlineFocus};
`;

@@ -563,3 +579,5 @@ }

}
}` : ''}
}`
: ''
}
}`;

@@ -604,4 +622,3 @@

) {
const hub = core.getCurrentHub();
const client = hub && hub.getClient();
const client = core.getCurrentHub().getClient();
const replay = includeReplay && client ? (client.getIntegrationById('Replay') ) : undefined;

@@ -797,9 +814,11 @@

Icon().el,
createElement(
'span',
{
className: 'widget__actor__text',
},
buttonLabel,
),
buttonLabel
? createElement(
'span',
{
className: 'widget__actor__text',
},
buttonLabel,
)
: null,
);

@@ -1290,3 +1309,7 @@

*/
function createWidget({ shadow, options, attachTo }) {
function createWidget({
shadow,
options: { shouldCreateActor = true, ...options },
attachTo,
}) {
let actor;

@@ -1432,3 +1455,3 @@ let dialog;

onCancel: () => {
hideDialog();
closeDialog();
showActor();

@@ -1458,5 +1481,5 @@ },

/**
* Hides the dialog
* Closes the dialog
*/
function hideDialog() {
function closeDialog() {
if (dialog) {

@@ -1477,3 +1500,3 @@ dialog.close();

if (dialog) {
hideDialog();
closeDialog();
const dialogEl = dialog.el;

@@ -1502,7 +1525,7 @@ dialogEl && dialogEl.remove();

if (!attachTo) {
if (attachTo) {
attachTo.addEventListener('click', handleActorClick);
} else if (shouldCreateActor) {
actor = Actor({ buttonLabel: options.buttonLabel, onClick: handleActorClick });
actor.el && shadow.appendChild(actor.el);
} else {
attachTo.addEventListener('click', handleActorClick);
}

@@ -1523,3 +1546,3 @@

openDialog,
hideDialog,
closeDialog,
removeDialog,

@@ -1666,11 +1689,3 @@ };

try {
// TODO: This is only here for hot reloading
if (this._host) {
this.remove();
}
const existingFeedback = doc.querySelector(`#${this.options.id}`);
if (existingFeedback) {
existingFeedback.remove();
}
// TODO: End hotloading
this._cleanupWidgetIfExists();

@@ -1684,5 +1699,5 @@ const { autoInject } = this.options;

this._widget = this._createWidget(this.options);
this._createWidget(this.options);
} catch (err) {
utils.logger.error(err);
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.error(err);
}

@@ -1692,2 +1707,31 @@ }

/**
* Allows user to open the dialog box. Creates a new widget if
* `autoInject` was false, otherwise re-uses the default widget that was
* created during initialization of the integration.
*/
openDialog() {
if (!this._widget) {
this._createWidget({ ...this.options, shouldCreateActor: false });
}
if (!this._widget) {
return;
}
this._widget.openDialog();
}
/**
* Closes the dialog for the default widget, if it exists
*/
closeDialog() {
if (!this._widget) {
// Nothing to do if widget does not exist
return;
}
this._widget.closeDialog();
}
/**
* Adds click listener to attached element to open a feedback dialog

@@ -1697,3 +1741,3 @@ */

try {
const options = mergeOptions(this.options, optionOverrides);
const options = mergeOptions(this.options, optionOverrides || {});

@@ -1705,3 +1749,3 @@ return this._ensureShadowHost(options, ({ shadow }) => {

if (!targetEl) {
utils.logger.error('[Feedback] Unable to attach to target element');
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.error('[Feedback] Unable to attach to target element');
return null;

@@ -1712,6 +1756,11 @@ }

this._widgets.add(widget);
if (!this._widget) {
this._widget = widget;
}
return widget;
});
} catch (err) {
utils.logger.error(err);
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.error(err);
return null;

@@ -1724,7 +1773,9 @@ }

*/
createWidget(optionOverrides) {
createWidget(
optionOverrides,
) {
try {
return this._createWidget(mergeOptions(this.options, optionOverrides));
return this._createWidget(mergeOptions(this.options, optionOverrides || {}));
} catch (err) {
utils.logger.error(err);
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.error(err);
return null;

@@ -1747,6 +1798,12 @@ }

this._widgets.delete(widget);
if (this._widget === widget) {
// TODO: is more clean-up needed? e.g. call remove()
this._widget = null;
}
return true;
}
} catch (err) {
utils.logger.error(err);
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.error(err);
}

@@ -1758,2 +1815,9 @@

/**
* Returns the default (first-created) widget
*/
getWidget() {
return this._widget;
}
/**
* Removes the Feedback integration (including host, shadow DOM, and all widgets)

@@ -1780,2 +1844,16 @@ */

/**
* Clean-up the widget if it already exists in the DOM. This shouldn't happen
* in prod, but can happen in development with hot module reloading.
*/
_cleanupWidgetIfExists() {
if (this._host) {
this.remove();
}
const existingFeedback = doc.querySelector(`#${this.options.id}`);
if (existingFeedback) {
existingFeedback.remove();
}
}
/**
* Creates a new widget, after ensuring shadow DOM exists

@@ -1793,2 +1871,7 @@ */

this._widgets.add(widget);
if (!this._widget) {
this._widget = widget;
}
return widget;

@@ -1809,7 +1892,8 @@ });

if (!this._shadow || !this._host) {
const { id, colorScheme, themeLight, themeDark } = options;
const { shadow, host } = createShadowHost({
id: options.id,
colorScheme: options.colorScheme,
themeLight: options.themeLight,
themeDark: options.themeDark,
id,
colorScheme,
themeLight,
themeDark,
});

@@ -1816,0 +1900,0 @@ this._shadow = shadow;

@@ -157,2 +157,3 @@ import { prepareEvent, getCurrentHub } from '@sentry/core';

const INHERIT = 'inherit';
const SUBMIT_COLOR = 'rgba(108, 95, 199, 1)';
const LIGHT_THEME = {

@@ -172,5 +173,7 @@ fontFamily: "'Helvetica Neue', Arial, sans-serif",

submitBackground: 'rgba(88, 74, 192, 1)',
submitBackgroundHover: 'rgba(108, 95, 199, 1)',
submitBorder: 'rgba(108, 95, 199, 1)',
submitBackgroundHover: SUBMIT_COLOR,
submitBorder: SUBMIT_COLOR,
submitOutlineFocus: '#29232f',
submitForeground: LIGHT_BACKGROUND,
submitForegroundHover: LIGHT_BACKGROUND,

@@ -180,3 +183,5 @@ cancelBackground: 'transparent',

cancelBorder: 'var(--border)',
cancelOutlineFocus: 'var(--input-outline-focus)',
cancelForeground: 'var(--foreground)',
cancelForegroundHover: 'var(--foreground)',

@@ -186,3 +191,3 @@ inputBackground: INHERIT,

inputBorder: 'var(--border)',
inputBorderFocus: 'rgba(108, 95, 199, 1)',
inputOutlineFocus: SUBMIT_COLOR,
};

@@ -417,5 +422,4 @@

.form__input:focus {
outline: 1px solid transparent;
outline-color: var(--input-border-focus);
.form__input:focus-visible {
outline: 1px auto var(--input-outline-focus);
}

@@ -455,3 +459,7 @@

background-color: var(--submit-background-hover);
color: var(--submit-foreground-hover);
}
.btn--primary:focus-visible {
outline: 1px auto var(--submit-outline-focus);
}

@@ -465,3 +473,7 @@ .btn--default {

background-color: var(--cancel-background-hover);
color: var(--cancel-foreground-hover);
}
.btn--default:focus-visible {
outline: 1px auto var(--cancel-outline-focus);
}

@@ -505,3 +517,5 @@ .success-message {

--submit-border: ${theme.submitBorder};
--submit-outline-focus: ${theme.submitOutlineFocus};
--submit-foreground: ${theme.submitForeground};
--submit-foreground-hover: ${theme.submitForegroundHover};

@@ -511,3 +525,5 @@ --cancel-background: ${theme.cancelBackground};

--cancel-border: ${theme.cancelBorder};
--cancel-outline-focus: ${theme.cancelOutlineFocus};
--cancel-foreground: ${theme.cancelForeground};
--cancel-foreground-hover: ${theme.cancelForegroundHover};

@@ -517,3 +533,3 @@ --input-background: ${theme.inputBackground};

--input-border: ${theme.inputBorder};
--input-border-focus: ${theme.inputBorderFocus};
--input-outline-focus: ${theme.inputOutlineFocus};
`;

@@ -561,3 +577,5 @@ }

}
}` : ''}
}`
: ''
}
}`;

@@ -602,4 +620,3 @@

) {
const hub = getCurrentHub();
const client = hub && hub.getClient();
const client = getCurrentHub().getClient();
const replay = includeReplay && client ? (client.getIntegrationById('Replay') ) : undefined;

@@ -795,9 +812,11 @@

Icon().el,
createElement(
'span',
{
className: 'widget__actor__text',
},
buttonLabel,
),
buttonLabel
? createElement(
'span',
{
className: 'widget__actor__text',
},
buttonLabel,
)
: null,
);

@@ -1288,3 +1307,7 @@

*/
function createWidget({ shadow, options, attachTo }) {
function createWidget({
shadow,
options: { shouldCreateActor = true, ...options },
attachTo,
}) {
let actor;

@@ -1430,3 +1453,3 @@ let dialog;

onCancel: () => {
hideDialog();
closeDialog();
showActor();

@@ -1456,5 +1479,5 @@ },

/**
* Hides the dialog
* Closes the dialog
*/
function hideDialog() {
function closeDialog() {
if (dialog) {

@@ -1475,3 +1498,3 @@ dialog.close();

if (dialog) {
hideDialog();
closeDialog();
const dialogEl = dialog.el;

@@ -1500,7 +1523,7 @@ dialogEl && dialogEl.remove();

if (!attachTo) {
if (attachTo) {
attachTo.addEventListener('click', handleActorClick);
} else if (shouldCreateActor) {
actor = Actor({ buttonLabel: options.buttonLabel, onClick: handleActorClick });
actor.el && shadow.appendChild(actor.el);
} else {
attachTo.addEventListener('click', handleActorClick);
}

@@ -1521,3 +1544,3 @@

openDialog,
hideDialog,
closeDialog,
removeDialog,

@@ -1664,11 +1687,3 @@ };

try {
// TODO: This is only here for hot reloading
if (this._host) {
this.remove();
}
const existingFeedback = doc.querySelector(`#${this.options.id}`);
if (existingFeedback) {
existingFeedback.remove();
}
// TODO: End hotloading
this._cleanupWidgetIfExists();

@@ -1682,5 +1697,5 @@ const { autoInject } = this.options;

this._widget = this._createWidget(this.options);
this._createWidget(this.options);
} catch (err) {
logger.error(err);
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(err);
}

@@ -1690,2 +1705,31 @@ }

/**
* Allows user to open the dialog box. Creates a new widget if
* `autoInject` was false, otherwise re-uses the default widget that was
* created during initialization of the integration.
*/
openDialog() {
if (!this._widget) {
this._createWidget({ ...this.options, shouldCreateActor: false });
}
if (!this._widget) {
return;
}
this._widget.openDialog();
}
/**
* Closes the dialog for the default widget, if it exists
*/
closeDialog() {
if (!this._widget) {
// Nothing to do if widget does not exist
return;
}
this._widget.closeDialog();
}
/**
* Adds click listener to attached element to open a feedback dialog

@@ -1695,3 +1739,3 @@ */

try {
const options = mergeOptions(this.options, optionOverrides);
const options = mergeOptions(this.options, optionOverrides || {});

@@ -1703,3 +1747,3 @@ return this._ensureShadowHost(options, ({ shadow }) => {

if (!targetEl) {
logger.error('[Feedback] Unable to attach to target element');
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Feedback] Unable to attach to target element');
return null;

@@ -1710,6 +1754,11 @@ }

this._widgets.add(widget);
if (!this._widget) {
this._widget = widget;
}
return widget;
});
} catch (err) {
logger.error(err);
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(err);
return null;

@@ -1722,7 +1771,9 @@ }

*/
createWidget(optionOverrides) {
createWidget(
optionOverrides,
) {
try {
return this._createWidget(mergeOptions(this.options, optionOverrides));
return this._createWidget(mergeOptions(this.options, optionOverrides || {}));
} catch (err) {
logger.error(err);
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(err);
return null;

@@ -1745,6 +1796,12 @@ }

this._widgets.delete(widget);
if (this._widget === widget) {
// TODO: is more clean-up needed? e.g. call remove()
this._widget = null;
}
return true;
}
} catch (err) {
logger.error(err);
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(err);
}

@@ -1756,2 +1813,9 @@

/**
* Returns the default (first-created) widget
*/
getWidget() {
return this._widget;
}
/**
* Removes the Feedback integration (including host, shadow DOM, and all widgets)

@@ -1778,2 +1842,16 @@ */

/**
* Clean-up the widget if it already exists in the DOM. This shouldn't happen
* in prod, but can happen in development with hot module reloading.
*/
_cleanupWidgetIfExists() {
if (this._host) {
this.remove();
}
const existingFeedback = doc.querySelector(`#${this.options.id}`);
if (existingFeedback) {
existingFeedback.remove();
}
}
/**
* Creates a new widget, after ensuring shadow DOM exists

@@ -1791,2 +1869,7 @@ */

this._widgets.add(widget);
if (!this._widget) {
this._widget = widget;
}
return widget;

@@ -1807,7 +1890,8 @@ });

if (!this._shadow || !this._host) {
const { id, colorScheme, themeLight, themeDark } = options;
const { shadow, host } = createShadowHost({
id: options.id,
colorScheme: options.colorScheme,
themeLight: options.themeLight,
themeDark: options.themeDark,
id,
colorScheme,
themeLight,
themeDark,
});

@@ -1814,0 +1898,0 @@ this._shadow = shadow;

@@ -15,11 +15,15 @@ export declare const DEFAULT_THEME: {

submitBorder: string;
submitOutlineFocus: string;
submitForeground: string;
submitForegroundHover: string;
cancelBackground: string;
cancelBackgroundHover: string;
cancelBorder: string;
cancelOutlineFocus: string;
cancelForeground: string;
cancelForegroundHover: string;
inputBackground: string;
inputForeground: string;
inputBorder: string;
inputBorderFocus: string;
inputOutlineFocus: string;
};

@@ -39,11 +43,15 @@ dark: {

submitBorder: string;
submitOutlineFocus: string;
submitForeground: string;
submitForegroundHover: string;
cancelBackground: string;
cancelBackgroundHover: string;
cancelBorder: string;
cancelOutlineFocus: string;
cancelForeground: string;
cancelForegroundHover: string;
inputBackground: string;
inputForeground: string;
inputBorder: string;
inputBorderFocus: string;
inputOutlineFocus: string;
};

@@ -50,0 +58,0 @@ };

import { Integration } from '@sentry/types';
import { FeedbackInternalOptions, OptionalFeedbackConfiguration, Widget } from './types';
import { FeedbackInternalOptions, FeedbackWidget, OptionalFeedbackConfiguration } from './types';
import { createShadowHost } from './widget/createShadowHost';

@@ -48,14 +48,30 @@ /**

/**
* Allows user to open the dialog box. Creates a new widget if
* `autoInject` was false, otherwise re-uses the default widget that was
* created during initialization of the integration.
*/
openDialog(): void;
/**
* Closes the dialog for the default widget, if it exists
*/
closeDialog(): void;
/**
* Adds click listener to attached element to open a feedback dialog
*/
attachTo(el: Element | string, optionOverrides: OptionalFeedbackConfiguration): Widget | null;
attachTo(el: Element | string, optionOverrides?: OptionalFeedbackConfiguration): FeedbackWidget | null;
/**
* Creates a new widget. Accepts partial options to override any options passed to constructor.
*/
createWidget(optionOverrides: OptionalFeedbackConfiguration): Widget | null;
createWidget(optionOverrides?: OptionalFeedbackConfiguration & {
shouldCreateActor?: boolean;
}): FeedbackWidget | null;
/**
* Removes a single widget
*/
removeWidget(widget: Widget | null | undefined): boolean;
removeWidget(widget: FeedbackWidget | null | undefined): boolean;
/**
* Returns the default (first-created) widget
*/
getWidget(): FeedbackWidget | null;
/**
* Removes the Feedback integration (including host, shadow DOM, and all widgets)

@@ -69,5 +85,12 @@ */

/**
* Clean-up the widget if it already exists in the DOM. This shouldn't happen
* in prod, but can happen in development with hot module reloading.
*/
protected _cleanupWidgetIfExists(): void;
/**
* Creates a new widget, after ensuring shadow DOM exists
*/
protected _createWidget(options: FeedbackInternalOptions): Widget | null;
protected _createWidget(options: FeedbackInternalOptions & {
shouldCreateActor?: boolean;
}): FeedbackWidget | null;
/**

@@ -74,0 +97,0 @@ * Ensures that shadow DOM exists and is added to the DOM

@@ -242,2 +242,6 @@ import { Event, Primitive } from '@sentry/types';

/**
* Border style for the submit button, in the focued state
*/
submitOutlineFocus: string;
/**
* Foreground color for the submit button

@@ -247,2 +251,6 @@ */

/**
* Foreground color for the submit button, in the hover state
*/
submitForegroundHover: string;
/**
* Background color for the cancel button

@@ -260,2 +268,6 @@ */

/**
* Border style for the cancel button, in the focued state
*/
cancelOutlineFocus: string;
/**
* Foreground color for the cancel button

@@ -265,2 +277,6 @@ */

/**
* Foreground color for the cancel button, in the hover state
*/
cancelForegroundHover: string;
/**
* Background color for form inputs

@@ -280,3 +296,3 @@ */

*/
inputBorderFocus: string;
inputOutlineFocus: string;
}

@@ -296,3 +312,3 @@ export interface FeedbackThemes {

*/
export interface Widget {
export interface FeedbackWidget {
actor: ActorComponent | undefined;

@@ -304,5 +320,5 @@ dialog: DialogComponent | undefined;

openDialog: () => void;
hideDialog: () => void;
closeDialog: () => void;
removeDialog: () => void;
}
//# sourceMappingURL=index.d.ts.map

@@ -1,6 +0,21 @@

import { FeedbackInternalOptions, Widget } from '../types';
import { FeedbackInternalOptions, FeedbackWidget } from '../types';
interface CreateWidgetParams {
/**
* Shadow DOM to append to
*/
shadow: ShadowRoot;
options: FeedbackInternalOptions;
/**
* Feedback integration options
*/
options: FeedbackInternalOptions & {
shouldCreateActor?: boolean;
};
/**
* An element to attach to, that when clicked, will open a dialog
*/
attachTo?: Element;
/**
* If false, will not create an actor
*/
shouldCreateActor?: boolean;
}

@@ -10,4 +25,4 @@ /**

*/
export declare function createWidget({ shadow, options, attachTo }: CreateWidgetParams): Widget;
export declare function createWidget({ shadow, options: { shouldCreateActor, ...options }, attachTo, }: CreateWidgetParams): FeedbackWidget;
export {};
//# sourceMappingURL=createWidget.d.ts.map

@@ -15,11 +15,15 @@ export declare const DEFAULT_THEME: {

submitBorder: string;
submitOutlineFocus: string;
submitForeground: string;
submitForegroundHover: string;
cancelBackground: string;
cancelBackgroundHover: string;
cancelBorder: string;
cancelOutlineFocus: string;
cancelForeground: string;
cancelForegroundHover: string;
inputBackground: string;
inputForeground: string;
inputBorder: string;
inputBorderFocus: string;
inputOutlineFocus: string;
};

@@ -39,11 +43,15 @@ dark: {

submitBorder: string;
submitOutlineFocus: string;
submitForeground: string;
submitForegroundHover: string;
cancelBackground: string;
cancelBackgroundHover: string;
cancelBorder: string;
cancelOutlineFocus: string;
cancelForeground: string;
cancelForegroundHover: string;
inputBackground: string;
inputForeground: string;
inputBorder: string;
inputBorderFocus: string;
inputOutlineFocus: string;
};

@@ -50,0 +58,0 @@ };

import type { Integration } from '@sentry/types';
import type { FeedbackInternalOptions, OptionalFeedbackConfiguration, Widget } from './types';
import type { FeedbackInternalOptions, FeedbackWidget, OptionalFeedbackConfiguration } from './types';
import { createShadowHost } from './widget/createShadowHost';

@@ -48,14 +48,30 @@ /**

/**
* Allows user to open the dialog box. Creates a new widget if
* `autoInject` was false, otherwise re-uses the default widget that was
* created during initialization of the integration.
*/
openDialog(): void;
/**
* Closes the dialog for the default widget, if it exists
*/
closeDialog(): void;
/**
* Adds click listener to attached element to open a feedback dialog
*/
attachTo(el: Element | string, optionOverrides: OptionalFeedbackConfiguration): Widget | null;
attachTo(el: Element | string, optionOverrides?: OptionalFeedbackConfiguration): FeedbackWidget | null;
/**
* Creates a new widget. Accepts partial options to override any options passed to constructor.
*/
createWidget(optionOverrides: OptionalFeedbackConfiguration): Widget | null;
createWidget(optionOverrides?: OptionalFeedbackConfiguration & {
shouldCreateActor?: boolean;
}): FeedbackWidget | null;
/**
* Removes a single widget
*/
removeWidget(widget: Widget | null | undefined): boolean;
removeWidget(widget: FeedbackWidget | null | undefined): boolean;
/**
* Returns the default (first-created) widget
*/
getWidget(): FeedbackWidget | null;
/**
* Removes the Feedback integration (including host, shadow DOM, and all widgets)

@@ -69,5 +85,12 @@ */

/**
* Clean-up the widget if it already exists in the DOM. This shouldn't happen
* in prod, but can happen in development with hot module reloading.
*/
protected _cleanupWidgetIfExists(): void;
/**
* Creates a new widget, after ensuring shadow DOM exists
*/
protected _createWidget(options: FeedbackInternalOptions): Widget | null;
protected _createWidget(options: FeedbackInternalOptions & {
shouldCreateActor?: boolean;
}): FeedbackWidget | null;
/**

@@ -74,0 +97,0 @@ * Ensures that shadow DOM exists and is added to the DOM

@@ -242,2 +242,6 @@ import type { Event, Primitive } from '@sentry/types';

/**
* Border style for the submit button, in the focued state
*/
submitOutlineFocus: string;
/**
* Foreground color for the submit button

@@ -247,2 +251,6 @@ */

/**
* Foreground color for the submit button, in the hover state
*/
submitForegroundHover: string;
/**
* Background color for the cancel button

@@ -260,2 +268,6 @@ */

/**
* Border style for the cancel button, in the focued state
*/
cancelOutlineFocus: string;
/**
* Foreground color for the cancel button

@@ -265,2 +277,6 @@ */

/**
* Foreground color for the cancel button, in the hover state
*/
cancelForegroundHover: string;
/**
* Background color for form inputs

@@ -280,3 +296,3 @@ */

*/
inputBorderFocus: string;
inputOutlineFocus: string;
}

@@ -296,3 +312,3 @@ export interface FeedbackThemes {

*/
export interface Widget {
export interface FeedbackWidget {
actor: ActorComponent | undefined;

@@ -304,5 +320,5 @@ dialog: DialogComponent | undefined;

openDialog: () => void;
hideDialog: () => void;
closeDialog: () => void;
removeDialog: () => void;
}
//# sourceMappingURL=index.d.ts.map

@@ -1,6 +0,21 @@

import type { FeedbackInternalOptions, Widget } from '../types';
import type { FeedbackInternalOptions, FeedbackWidget } from '../types';
interface CreateWidgetParams {
/**
* Shadow DOM to append to
*/
shadow: ShadowRoot;
options: FeedbackInternalOptions;
/**
* Feedback integration options
*/
options: FeedbackInternalOptions & {
shouldCreateActor?: boolean;
};
/**
* An element to attach to, that when clicked, will open a dialog
*/
attachTo?: Element;
/**
* If false, will not create an actor
*/
shouldCreateActor?: boolean;
}

@@ -10,4 +25,4 @@ /**

*/
export declare function createWidget({ shadow, options, attachTo }: CreateWidgetParams): Widget;
export declare function createWidget({ shadow, options: { shouldCreateActor, ...options }, attachTo, }: CreateWidgetParams): FeedbackWidget;
export {};
//# sourceMappingURL=createWidget.d.ts.map
{
"name": "@sentry-internal/feedback",
"version": "0.0.1-alpha.9",
"version": "0.0.1-alpha.10",
"description": "Sentry SDK integration for user feedback",

@@ -5,0 +5,0 @@ "repository": "git://github.com/getsentry/sentry-javascript.git",

@@ -97,3 +97,3 @@ <p align="center">

| `namePlaceholder` | `Your Name` | The placeholder for the name input field. |
| `emailLabel` | `Email` | The label of the email input field. ||
| `emailLabel` | `Email` | The label of the email input field. |
| `emailPlaceholder` | `your.email@example.org` | The placeholder for the email input field. |

@@ -130,11 +130,15 @@ | `messageLabel` | `Description` | The label for the feedback description input field. |

| `submitBorder` | `--submit-border` | `rgba(108, 95, 199, 1)` | `rgba(108, 95, 199, 1)` | Border style for the submit button |
| `submitOutlineFocus` | `--submit-outline-focus` | `rgba(108, 95, 199, 1)` | `rgba(108, 95, 199, 1)` | Outline color for the submit button, in the focused state |
| `submitForeground` | `--submit-foreground` | `#ffffff` | `#ffffff` | Foreground color for the submit button |
| `submitForegroundHover` | `--submit-foreground-hover` | `#ffffff` | `#ffffff` | Foreground color for the submit button when hovering |
| `cancelBackground` | `--cancel-background` | `transparent` | `transparent` | Background color for the cancel button |
| `cancelBackgroundHover` | `--cancel-background-hover` | `var(--background-hover)` | `var(--background-hover)` | Background color when hovering over the cancel button |
| `cancelBorder` | `--cancel-border` | `var(--border)` | `var(--border)` | Border style for the cancel button |
| `cancelOutlineFocus` | `--cancel-outline-focus` | `var(--input-outline-focus)` | `var(--input-outline-focus)` | Outline color for the cancel button, in the focused state |
| `cancelForeground` | `--cancel-foreground` | `var(--foreground)` | `var(--foreground)` | Foreground color for the cancel button |
| `cancelForegroundHover` | `--cancel-foreground-hover` | `var(--foreground)` | `var(--foreground)` | Foreground color for the cancel button when hovering |
| `inputBackground` | `--input-background` | `inherit` | `inherit` | Background color for form inputs |
| `inputForeground` | `--input-foreground` | `inherit` | `inherit` | Foreground color for form inputs |
| `inputBorder` | `--input-border` | `var(--border)` | `var(--border)` | Border styles for form inputs |
| `inputBorderFocus` | `--input-border-focus` | `rgba(108, 95, 199, 1)` | `rgba(108, 95, 199, 1)` | Border styles for form inputs when focused |
| `inputOutlineFocus` | `--input-outline-focus` | `rgba(108, 95, 199, 1)` | `rgba(108, 95, 199, 1)` | Outline color for form inputs when focused |

@@ -204,2 +208,25 @@ Here is an example of customizing only the background color for the light theme using the Feedback constructor configuration.

Alternatively you can call `feedback.openDialog()`:
```typescript
import {BrowserClient, getCurrentHub} from '@sentry/react';
import {Feedback} from '@sentry-internal/feedback';
function MyFeedbackButton() {
const client = hub && getCurrentHub().getClient<BrowserClient>();
const feedback = client?.getIntegration(Feedback);
// Don't render custom feedback button if Feedback integration not installed
if (!feedback) {
return null;
}
return (
<button type="button" onClick={() => feedback.openDialog()}>
Give me feedback
</button>
)
}
```
### Bring Your Own Widget

@@ -206,0 +233,0 @@

const LIGHT_BACKGROUND = '#ffffff';
const INHERIT = 'inherit';
const SUBMIT_COLOR = 'rgba(108, 95, 199, 1)';
const LIGHT_THEME = {

@@ -17,5 +18,7 @@ fontFamily: "'Helvetica Neue', Arial, sans-serif",

submitBackground: 'rgba(88, 74, 192, 1)',
submitBackgroundHover: 'rgba(108, 95, 199, 1)',
submitBorder: 'rgba(108, 95, 199, 1)',
submitBackgroundHover: SUBMIT_COLOR,
submitBorder: SUBMIT_COLOR,
submitOutlineFocus: '#29232f',
submitForeground: LIGHT_BACKGROUND,
submitForegroundHover: LIGHT_BACKGROUND,

@@ -25,3 +28,5 @@ cancelBackground: 'transparent',

cancelBorder: 'var(--border)',
cancelOutlineFocus: 'var(--input-outline-focus)',
cancelForeground: 'var(--foreground)',
cancelForegroundHover: 'var(--foreground)',

@@ -31,3 +36,3 @@ inputBackground: INHERIT,

inputBorder: 'var(--border)',
inputBorderFocus: 'rgba(108, 95, 199, 1)',
inputOutlineFocus: SUBMIT_COLOR,
};

@@ -34,0 +39,0 @@

@@ -19,3 +19,3 @@ import { WINDOW } from '@sentry/browser';

} from './constants';
import type { FeedbackInternalOptions, OptionalFeedbackConfiguration, Widget } from './types';
import type { FeedbackInternalOptions, FeedbackWidget, OptionalFeedbackConfiguration } from './types';
import { mergeOptions } from './util/mergeOptions';

@@ -52,3 +52,3 @@ import { createActorStyles } from './widget/Actor.css';

*/
private _widget: Widget | null;
private _widget: FeedbackWidget | null;

@@ -58,3 +58,3 @@ /**

*/
private _widgets: Set<Widget>;
private _widgets: Set<FeedbackWidget>;

@@ -172,11 +172,3 @@ /**

try {
// TODO: This is only here for hot reloading
if (this._host) {
this.remove();
}
const existingFeedback = doc.querySelector(`#${this.options.id}`);
if (existingFeedback) {
existingFeedback.remove();
}
// TODO: End hotloading
this._cleanupWidgetIfExists();

@@ -190,5 +182,5 @@ const { autoInject } = this.options;

this._widget = this._createWidget(this.options);
this._createWidget(this.options);
} catch (err) {
logger.error(err);
__DEBUG_BUILD__ && logger.error(err);
}

@@ -198,9 +190,38 @@ }

/**
* Allows user to open the dialog box. Creates a new widget if
* `autoInject` was false, otherwise re-uses the default widget that was
* created during initialization of the integration.
*/
public openDialog(): void {
if (!this._widget) {
this._createWidget({ ...this.options, shouldCreateActor: false });
}
if (!this._widget) {
return;
}
this._widget.openDialog();
}
/**
* Closes the dialog for the default widget, if it exists
*/
public closeDialog(): void {
if (!this._widget) {
// Nothing to do if widget does not exist
return;
}
this._widget.closeDialog();
}
/**
* Adds click listener to attached element to open a feedback dialog
*/
public attachTo(el: Element | string, optionOverrides: OptionalFeedbackConfiguration): Widget | null {
public attachTo(el: Element | string, optionOverrides?: OptionalFeedbackConfiguration): FeedbackWidget | null {
try {
const options = mergeOptions(this.options, optionOverrides);
const options = mergeOptions(this.options, optionOverrides || {});
return this._ensureShadowHost<Widget | null>(options, ({ shadow }) => {
return this._ensureShadowHost<FeedbackWidget | null>(options, ({ shadow }) => {
const targetEl =

@@ -210,3 +231,3 @@ typeof el === 'string' ? doc.querySelector(el) : typeof el.addEventListener === 'function' ? el : null;

if (!targetEl) {
logger.error('[Feedback] Unable to attach to target element');
__DEBUG_BUILD__ && logger.error('[Feedback] Unable to attach to target element');
return null;

@@ -217,6 +238,11 @@ }

this._widgets.add(widget);
if (!this._widget) {
this._widget = widget;
}
return widget;
});
} catch (err) {
logger.error(err);
__DEBUG_BUILD__ && logger.error(err);
return null;

@@ -229,7 +255,9 @@ }

*/
public createWidget(optionOverrides: OptionalFeedbackConfiguration): Widget | null {
public createWidget(
optionOverrides?: OptionalFeedbackConfiguration & { shouldCreateActor?: boolean },
): FeedbackWidget | null {
try {
return this._createWidget(mergeOptions(this.options, optionOverrides));
return this._createWidget(mergeOptions(this.options, optionOverrides || {}));
} catch (err) {
logger.error(err);
__DEBUG_BUILD__ && logger.error(err);
return null;

@@ -242,3 +270,3 @@ }

*/
public removeWidget(widget: Widget | null | undefined): boolean {
public removeWidget(widget: FeedbackWidget | null | undefined): boolean {
if (!widget) {

@@ -253,6 +281,12 @@ return false;

this._widgets.delete(widget);
if (this._widget === widget) {
// TODO: is more clean-up needed? e.g. call remove()
this._widget = null;
}
return true;
}
} catch (err) {
logger.error(err);
__DEBUG_BUILD__ && logger.error(err);
}

@@ -264,2 +298,9 @@

/**
* Returns the default (first-created) widget
*/
public getWidget(): FeedbackWidget | null {
return this._widget;
}
/**
* Removes the Feedback integration (including host, shadow DOM, and all widgets)

@@ -286,6 +327,20 @@ */

/**
* Clean-up the widget if it already exists in the DOM. This shouldn't happen
* in prod, but can happen in development with hot module reloading.
*/
protected _cleanupWidgetIfExists(): void {
if (this._host) {
this.remove();
}
const existingFeedback = doc.querySelector(`#${this.options.id}`);
if (existingFeedback) {
existingFeedback.remove();
}
}
/**
* Creates a new widget, after ensuring shadow DOM exists
*/
protected _createWidget(options: FeedbackInternalOptions): Widget | null {
return this._ensureShadowHost<Widget>(options, ({ shadow }) => {
protected _createWidget(options: FeedbackInternalOptions & { shouldCreateActor?: boolean }): FeedbackWidget | null {
return this._ensureShadowHost<FeedbackWidget>(options, ({ shadow }) => {
const widget = createWidget({ shadow, options });

@@ -299,2 +354,7 @@

this._widgets.add(widget);
if (!this._widget) {
this._widget = widget;
}
return widget;

@@ -315,7 +375,8 @@ });

if (!this._shadow || !this._host) {
const { id, colorScheme, themeLight, themeDark } = options;
const { shadow, host } = createShadowHost({
id: options.id,
colorScheme: options.colorScheme,
themeLight: options.themeLight,
themeDark: options.themeDark,
id,
colorScheme,
themeLight,
themeDark,
});

@@ -322,0 +383,0 @@ this._shadow = shadow;

@@ -22,4 +22,3 @@ import type { BrowserClient, Replay } from '@sentry/browser';

): ReturnType<typeof sendFeedbackRequest> {
const hub = getCurrentHub();
const client = hub && hub.getClient<BrowserClient>();
const client = getCurrentHub().getClient<BrowserClient>();
const replay = includeReplay && client ? (client.getIntegrationById('Replay') as Replay | undefined) : undefined;

@@ -26,0 +25,0 @@

@@ -273,2 +273,6 @@ import type { Event, Primitive } from '@sentry/types';

/**
* Border style for the submit button, in the focued state
*/
submitOutlineFocus: string;
/**
* Foreground color for the submit button

@@ -279,2 +283,7 @@ */

/**
* Foreground color for the submit button, in the hover state
*/
submitForegroundHover: string;
/**
* Background color for the cancel button

@@ -292,5 +301,13 @@ */

/**
* Border style for the cancel button, in the focued state
*/
cancelOutlineFocus: string;
/**
* Foreground color for the cancel button
*/
cancelForeground: string;
/**
* Foreground color for the cancel button, in the hover state
*/
cancelForegroundHover: string;

@@ -312,3 +329,3 @@ /**

*/
inputBorderFocus: string;
inputOutlineFocus: string;
}

@@ -331,3 +348,3 @@

*/
export interface Widget {
export interface FeedbackWidget {
actor: ActorComponent | undefined;

@@ -341,4 +358,4 @@ dialog: DialogComponent | undefined;

openDialog: () => void;
hideDialog: () => void;
closeDialog: () => void;
removeDialog: () => void;
}

@@ -37,9 +37,11 @@ import type { FeedbackComponent, FeedbackInternalOptions } from '../types';

Icon().el,
createElement(
'span',
{
className: 'widget__actor__text',
},
buttonLabel,
),
buttonLabel
? createElement(
'span',
{
className: 'widget__actor__text',
},
buttonLabel,
)
: null,
);

@@ -46,0 +48,0 @@

import { getCurrentHub } from '@sentry/core';
import { logger } from '@sentry/utils';
import type { FeedbackFormData, FeedbackInternalOptions, Widget } from '../types';
import type { FeedbackFormData, FeedbackInternalOptions, FeedbackWidget } from '../types';
import { handleFeedbackSubmit } from '../util/handleFeedbackSubmit';

@@ -13,5 +13,21 @@ import type { ActorComponent } from './Actor';

interface CreateWidgetParams {
/**
* Shadow DOM to append to
*/
shadow: ShadowRoot;
options: FeedbackInternalOptions;
/**
* Feedback integration options
*/
options: FeedbackInternalOptions & { shouldCreateActor?: boolean };
/**
* An element to attach to, that when clicked, will open a dialog
*/
attachTo?: Element;
/**
* If false, will not create an actor
*/
shouldCreateActor?: boolean;
}

@@ -22,3 +38,7 @@

*/
export function createWidget({ shadow, options, attachTo }: CreateWidgetParams): Widget {
export function createWidget({
shadow,
options: { shouldCreateActor = true, ...options },
attachTo,
}: CreateWidgetParams): FeedbackWidget {
let actor: ActorComponent | undefined;

@@ -164,3 +184,3 @@ let dialog: DialogComponent | undefined;

onCancel: () => {
hideDialog();
closeDialog();
showActor();

@@ -190,5 +210,5 @@ },

/**
* Hides the dialog
* Closes the dialog
*/
function hideDialog(): void {
function closeDialog(): void {
if (dialog) {

@@ -209,3 +229,3 @@ dialog.close();

if (dialog) {
hideDialog();
closeDialog();
const dialogEl = dialog.el;

@@ -234,7 +254,7 @@ dialogEl && dialogEl.remove();

if (!attachTo) {
if (attachTo) {
attachTo.addEventListener('click', handleActorClick);
} else if (shouldCreateActor) {
actor = Actor({ buttonLabel: options.buttonLabel, onClick: handleActorClick });
actor.el && shadow.appendChild(actor.el);
} else {
attachTo.addEventListener('click', handleActorClick);
}

@@ -255,5 +275,5 @@

openDialog,
hideDialog,
closeDialog,
removeDialog,
};
}

@@ -125,5 +125,4 @@ /**

.form__input:focus {
outline: 1px solid transparent;
outline-color: var(--input-border-focus);
.form__input:focus-visible {
outline: 1px auto var(--input-outline-focus);
}

@@ -163,3 +162,7 @@

background-color: var(--submit-background-hover);
color: var(--submit-foreground-hover);
}
.btn--primary:focus-visible {
outline: 1px auto var(--submit-outline-focus);
}

@@ -173,3 +176,7 @@ .btn--default {

background-color: var(--cancel-background-hover);
color: var(--cancel-foreground-hover);
}
.btn--default:focus-visible {
outline: 1px auto var(--cancel-outline-focus);
}

@@ -176,0 +183,0 @@ .success-message {

@@ -16,3 +16,5 @@ import type { FeedbackTheme, FeedbackThemes } from '../types';

--submit-border: ${theme.submitBorder};
--submit-outline-focus: ${theme.submitOutlineFocus};
--submit-foreground: ${theme.submitForeground};
--submit-foreground-hover: ${theme.submitForegroundHover};

@@ -22,3 +24,5 @@ --cancel-background: ${theme.cancelBackground};

--cancel-border: ${theme.cancelBorder};
--cancel-outline-focus: ${theme.cancelOutlineFocus};
--cancel-foreground: ${theme.cancelForeground};
--cancel-foreground-hover: ${theme.cancelForegroundHover};

@@ -28,3 +32,3 @@ --input-background: ${theme.inputBackground};

--input-border: ${theme.inputBorder};
--input-border-focus: ${theme.inputBorderFocus};
--input-outline-focus: ${theme.inputOutlineFocus};
`;

@@ -72,3 +76,5 @@ }

}
}` : ''}
}`
: ''
}
}`;

@@ -75,0 +81,0 @@

@@ -28,2 +28,3 @@ import {

showName: true,
showBranding: false,
useSentryUser: {

@@ -69,3 +70,3 @@ email: 'email',

function createShadowAndWidget(
feedbackOptions?: Partial<FeedbackInternalOptions>,
feedbackOptions?: Partial<FeedbackInternalOptions> & { shouldCreateActor?: boolean },
createWidgetOptions?: Partial<Parameters<typeof createWidget>[0]>,

@@ -97,9 +98,20 @@ ) {

it('creates widget with actor', () => {
const { widget } = createShadowAndWidget();
const { shadow, widget } = createShadowAndWidget();
expect(widget.actor?.el).toBeInstanceOf(HTMLButtonElement);
expect(widget.actor?.el?.textContent).toBe(DEFAULT_OPTIONS.buttonLabel);
const actorEl = widget.actor?.el as HTMLButtonElement;
expect(actorEl.textContent).toBe(DEFAULT_OPTIONS.buttonLabel);
// No dialog until actor is clicked
expect(widget.dialog).toBeUndefined();
expect(shadow.contains(actorEl)).toBe(true);
});
it('creates widget without actor', () => {
const { widget } = createShadowAndWidget({
shouldCreateActor: false,
});
expect(widget.actor?.el).toBeUndefined();
// No dialog until actor is clicked
expect(widget.dialog).toBeUndefined();
});
it('clicking on actor opens dialog and hides the actor', () => {

@@ -106,0 +118,0 @@ const onDialogOpen = jest.fn();

@@ -11,2 +11,3 @@ import type { DialogProps } from '../../src/widget/Dialog';

showEmail = true,
showBranding = false,
isAnonymous = false,

@@ -16,2 +17,3 @@ formTitle = 'Feedback',

defaultEmail = 'foo@example.com',
colorScheme = 'light',
nameLabel = 'Name',

@@ -33,4 +35,6 @@ namePlaceholder = 'Your full name',

showEmail,
showBranding,
defaultName,
defaultEmail,
colorScheme,
nameLabel,

@@ -37,0 +41,0 @@ namePlaceholder,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc