Skip to content

Commit 9f19754

Browse files
authored
ref(feedback): Simplify feedback function params (#11957)
We can simplify the function params and only pass options around most of the time. I also moved some dialog specific css variables into dialog.css.ts so they can be async loaded, which depends on the options config. Before submitting a pull request, please take a look at our [Contributing](https://github.com/getsentry/sentry-javascript/blob/master/CONTRIBUTING.md) guidelines and verify: - [ ] If you've added code that should be tested, please add tests. - [ ] Ensure your code lints and the test suite passes (`yarn lint`) & (`yarn test`).
1 parent f9b9132 commit 9f19754

File tree

7 files changed

+93
-102
lines changed

7 files changed

+93
-102
lines changed

packages/feedback/src/core/createMainStyles.ts

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,54 +11,26 @@ function getThemedCssVariables(theme: FeedbackInternalOptions['themeLight']): st
1111
--border: ${theme.border};
1212
--border-radius: ${theme.borderRadius};
1313
--box-shadow: ${theme.boxShadow};
14-
15-
--submit-background: ${theme.submitBackground};
16-
--submit-background-hover: ${theme.submitBackgroundHover};
17-
--submit-border: ${theme.submitBorder};
18-
--submit-outline-focus: ${theme.submitOutlineFocus};
19-
--submit-foreground: ${theme.submitForeground};
20-
--submit-foreground-hover: ${theme.submitForegroundHover};
21-
22-
--cancel-background: ${theme.cancelBackground};
23-
--cancel-background-hover: ${theme.cancelBackgroundHover};
24-
--cancel-border: ${theme.cancelBorder};
25-
--cancel-outline-focus: ${theme.cancelOutlineFocus};
26-
--cancel-foreground: ${theme.cancelForeground};
27-
--cancel-foreground-hover: ${theme.cancelForegroundHover};
28-
29-
--input-background: ${theme.inputBackground};
30-
--input-foreground: ${theme.inputForeground};
31-
--input-border: ${theme.inputBorder};
32-
--input-outline-focus: ${theme.inputOutlineFocus};
33-
34-
--form-border-radius: ${theme.formBorderRadius};
35-
--form-content-border-radius: ${theme.formContentBorderRadius};
3614
`;
3715
}
3816

3917
/**
4018
* Creates <style> element for widget actor (button that opens the dialog)
4119
*/
42-
export function createMainStyles(
43-
colorScheme: 'system' | 'dark' | 'light',
44-
themes: Pick<FeedbackInternalOptions, 'themeLight' | 'themeDark'>,
45-
): HTMLStyleElement {
20+
export function createMainStyles({ colorScheme, themeDark, themeLight }: FeedbackInternalOptions): HTMLStyleElement {
4621
const style = DOCUMENT.createElement('style');
4722
style.textContent = `
4823
:host {
49-
--z-index: ${themes.themeLight.zIndex};
50-
--font-family: ${themes.themeLight.fontFamily};
51-
--font-size: ${themes.themeLight.fontSize};
24+
--z-index: ${themeLight.zIndex};
25+
--font-family: ${themeLight.fontFamily};
26+
--font-size: ${themeLight.fontSize};
5227
5328
font-family: var(--font-family);
5429
font-size: var(--font-size);
5530
5631
--page-margin: 16px;
5732
--actor-inset: auto var(--page-margin) var(--page-margin) auto;
5833
59-
--dialog-inset: auto var(--page-margin) var(--page-margin) auto;
60-
--dialog-padding: 24px;
61-
6234
.brand-link path {
6335
fill: ${colorScheme === 'dark' ? '#fff' : '#362d59'};
6436
}
@@ -69,20 +41,21 @@ export function createMainStyles(
6941
}
7042
}
7143
72-
${getThemedCssVariables(colorScheme === 'dark' ? themes.themeDark : themes.themeLight)}
44+
${getThemedCssVariables(colorScheme === 'dark' ? themeDark : themeLight)}
7345
}
7446
7547
${
7648
colorScheme === 'system'
7749
? `
7850
@media (prefers-color-scheme: dark) {
7951
:host {
80-
${getThemedCssVariables(themes.themeDark)}
52+
${getThemedCssVariables(themeDark)}
8153
}
8254
}`
8355
: ''
8456
}
85-
}`;
57+
}
58+
`;
8659

8760
return style;
8861
}

packages/feedback/src/core/integration.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ export const buildFeedbackIntegration = ({
8484

8585
// FeedbackTextConfiguration
8686
addScreenshotButtonLabel = ADD_SCREENSHOT_LABEL,
87-
triggerLabel = TRIGGER_LABEL,
8887
cancelButtonLabel = CANCEL_BUTTON_LABEL,
8988
confirmButtonLabel = CONFIRM_BUTTON_LABEL,
9089
emailLabel = EMAIL_LABEL,
@@ -98,6 +97,7 @@ export const buildFeedbackIntegration = ({
9897
removeScreenshotButtonLabel = REMOVE_SCREENSHOT_LABEL,
9998
submitButtonLabel = SUBMIT_BUTTON_LABEL,
10099
successMessageText = SUCCESS_MESSAGE_TEXT,
100+
triggerLabel = TRIGGER_LABEL,
101101

102102
// FeedbackCallbacks
103103
onFormOpen,
@@ -163,7 +163,7 @@ export const buildFeedbackIntegration = ({
163163
DOCUMENT.body.appendChild(host);
164164

165165
_shadow = host.attachShadow({ mode: 'open' });
166-
_shadow.appendChild(createMainStyles(options.colorScheme, options));
166+
_shadow.appendChild(createMainStyles(options));
167167
}
168168
return _shadow as ShadowRoot;
169169
};

packages/feedback/src/modal/components/Dialog.css.ts

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { FeedbackInternalOptions } from '@sentry/types';
12
import { DOCUMENT } from '../../constants';
23

34
const DIALOG = `
@@ -237,19 +238,64 @@ const SUCCESS = `
237238
}
238239
`;
239240

241+
function getThemedCssVariables(theme: FeedbackInternalOptions['themeLight']): string {
242+
return `
243+
--submit-background: ${theme.submitBackground};
244+
--submit-background-hover: ${theme.submitBackgroundHover};
245+
--submit-border: ${theme.submitBorder};
246+
--submit-outline-focus: ${theme.submitOutlineFocus};
247+
--submit-foreground: ${theme.submitForeground};
248+
--submit-foreground-hover: ${theme.submitForegroundHover};
249+
250+
--cancel-background: ${theme.cancelBackground};
251+
--cancel-background-hover: ${theme.cancelBackgroundHover};
252+
--cancel-border: ${theme.cancelBorder};
253+
--cancel-outline-focus: ${theme.cancelOutlineFocus};
254+
--cancel-foreground: ${theme.cancelForeground};
255+
--cancel-foreground-hover: ${theme.cancelForegroundHover};
256+
257+
--input-background: ${theme.inputBackground};
258+
--input-foreground: ${theme.inputForeground};
259+
--input-border: ${theme.inputBorder};
260+
--input-outline-focus: ${theme.inputOutlineFocus};
261+
262+
--form-border-radius: ${theme.formBorderRadius};
263+
--form-content-border-radius: ${theme.formContentBorderRadius};
264+
`;
265+
}
266+
240267
/**
241268
* Creates <style> element for widget dialog
242269
*/
243-
export function createDialogStyles(): HTMLStyleElement {
270+
export function createDialogStyles({ colorScheme, themeDark, themeLight }: FeedbackInternalOptions): HTMLStyleElement {
244271
const style = DOCUMENT.createElement('style');
245272

246273
style.textContent = `
247-
${DIALOG}
248-
${DIALOG_HEADER}
249-
${FORM}
250-
${BUTTON}
251-
${SUCCESS}
252-
`;
274+
:host {
275+
--dialog-inset: auto var(--page-margin) var(--page-margin) auto;
276+
--dialog-padding: 24px;
277+
278+
${getThemedCssVariables(colorScheme === 'dark' ? themeDark : themeLight)}
279+
}
280+
281+
${
282+
colorScheme === 'system'
283+
? `
284+
@media (prefers-color-scheme: dark) {
285+
:host {
286+
${getThemedCssVariables(themeDark)}
287+
}
288+
}`
289+
: ''
290+
}
291+
}
292+
293+
${DIALOG}
294+
${DIALOG_HEADER}
295+
${FORM}
296+
${BUTTON}
297+
${SUCCESS}
298+
`;
253299

254300
return style;
255301
}

packages/feedback/src/modal/components/Dialog.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FeedbackFormData } from '@sentry/types';
1+
import type { FeedbackFormData, FeedbackInternalOptions } from '@sentry/types';
22
// biome-ignore lint/nursery/noUnusedImports: reason
33
import { Fragment, h } from 'preact'; // eslint-disable-line @typescript-eslint/no-unused-vars
44
import type { VNode } from 'preact';
@@ -11,12 +11,13 @@ import { Form } from './Form';
1111
import { SuccessIcon } from './SuccessIcon';
1212

1313
interface Props extends HeaderProps, FormProps {
14-
successMessageText: string;
1514
onFormSubmitted: () => void;
1615
open: boolean;
16+
options: FeedbackInternalOptions;
1717
}
1818

19-
export function Dialog({ open, onFormSubmitted, successMessageText, ...props }: Props): VNode {
19+
export function Dialog({ open, onFormSubmitted, ...props }: Props): VNode {
20+
const options = props.options;
2021
const successIconHtml = useMemo(() => ({ __html: SuccessIcon().outerHTML }), []);
2122

2223
const [timeoutId, setTimeoutId] = useState<NodeJS.Timeout | null>(null);
@@ -46,7 +47,7 @@ export function Dialog({ open, onFormSubmitted, successMessageText, ...props }:
4647
<Fragment>
4748
{timeoutId ? (
4849
<div class="success-message" onClick={handleOnSuccessClick}>
49-
{successMessageText}
50+
{options.successMessageText}
5051
<span class="success-icon" dangerouslySetInnerHTML={successIconHtml} />
5152
</div>
5253
) : (

packages/feedback/src/modal/components/DialogHeader.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@ import { useMemo } from 'preact/hooks';
66
import { SentryLogo } from './SentryLogo';
77

88
export interface Props {
9-
formTitle: FeedbackInternalOptions['formTitle'];
10-
showBranding: FeedbackInternalOptions['showBranding'];
9+
options: FeedbackInternalOptions;
1110
}
1211

13-
export function DialogHeader({ formTitle, showBranding }: Props): VNode {
12+
export function DialogHeader({ options }: Props): VNode {
1413
const logoHtml = useMemo(() => ({ __html: SentryLogo().outerHTML }), []);
1514

1615
return (
1716
<h2 class="dialog__header">
18-
{formTitle}
19-
{showBranding ? (
17+
{options.formTitle}
18+
{options.showBranding ? (
2019
<a
2120
class="brand-link"
2221
target="_blank"

packages/feedback/src/modal/components/Form.tsx

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,8 @@ import { FEEDBACK_WIDGET_SOURCE } from '../../constants';
1313
import { DEBUG_BUILD } from '../../util/debug-build';
1414
import { getMissingFields } from '../../util/validate';
1515

16-
export interface Props
17-
extends Pick<
18-
FeedbackInternalOptions,
19-
| 'addScreenshotButtonLabel'
20-
| 'removeScreenshotButtonLabel'
21-
| 'cancelButtonLabel'
22-
| 'emailLabel'
23-
| 'emailPlaceholder'
24-
| 'isEmailRequired'
25-
| 'isNameRequired'
26-
| 'messageLabel'
27-
| 'messagePlaceholder'
28-
| 'nameLabel'
29-
| 'namePlaceholder'
30-
| 'showEmail'
31-
| 'showName'
32-
| 'submitButtonLabel'
33-
| 'isRequiredLabel'
34-
> {
16+
export interface Props extends Pick<FeedbackInternalOptions, 'showEmail' | 'showName'> {
17+
options: FeedbackInternalOptions;
3518
defaultEmail: string;
3619
defaultName: string;
3720
onFormClose: () => void;
@@ -50,29 +33,33 @@ function retrieveStringValue(formData: FormData, key: string): string {
5033
}
5134

5235
export function Form({
53-
addScreenshotButtonLabel,
54-
removeScreenshotButtonLabel,
55-
cancelButtonLabel,
36+
options,
5637
defaultEmail,
5738
defaultName,
58-
emailLabel,
59-
emailPlaceholder,
60-
isEmailRequired,
61-
isNameRequired,
62-
messageLabel,
63-
messagePlaceholder,
64-
nameLabel,
65-
namePlaceholder,
39+
6640
onFormClose,
6741
onSubmit,
6842
onSubmitSuccess,
6943
onSubmitError,
7044
showEmail,
7145
showName,
72-
submitButtonLabel,
73-
isRequiredLabel,
7446
screenshotInput,
7547
}: Props): VNode {
48+
const {
49+
addScreenshotButtonLabel,
50+
removeScreenshotButtonLabel,
51+
cancelButtonLabel,
52+
emailLabel,
53+
emailPlaceholder,
54+
isEmailRequired,
55+
isNameRequired,
56+
messageLabel,
57+
messagePlaceholder,
58+
nameLabel,
59+
namePlaceholder,
60+
submitButtonLabel,
61+
isRequiredLabel,
62+
} = options;
7663
// TODO: set a ref on the form, and whenever an input changes call proceessForm() and setError()
7764
const [error, setError] = useState<null | string>(null);
7865

packages/feedback/src/modal/integration.tsx

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const feedbackModalIntegration = ((): FeedbackModalIntegration => {
1616
const user = getCurrentScope().getUser() || getIsolationScope().getUser() || getGlobalScope().getUser();
1717

1818
const el = DOCUMENT.createElement('div');
19-
const style = createDialogStyles();
19+
const style = createDialogStyles(options);
2020

2121
let originalOverflow = '';
2222
const dialog = {
@@ -50,27 +50,12 @@ export const feedbackModalIntegration = ((): FeedbackModalIntegration => {
5050
const renderContent = (open: boolean): void => {
5151
render(
5252
<Dialog
53+
options={options}
5354
screenshotInput={screenshotInput}
54-
showBranding={options.showBranding}
5555
showName={options.showName || options.isNameRequired}
5656
showEmail={options.showEmail || options.isEmailRequired}
57-
isNameRequired={options.isNameRequired}
58-
isEmailRequired={options.isEmailRequired}
59-
formTitle={options.formTitle}
60-
cancelButtonLabel={options.cancelButtonLabel}
61-
submitButtonLabel={options.submitButtonLabel}
62-
emailLabel={options.emailLabel}
63-
emailPlaceholder={options.emailPlaceholder}
64-
messageLabel={options.messageLabel}
65-
messagePlaceholder={options.messagePlaceholder}
66-
nameLabel={options.nameLabel}
67-
namePlaceholder={options.namePlaceholder}
6857
defaultName={(userKey && user && user[userKey.name]) || ''}
6958
defaultEmail={(userKey && user && user[userKey.email]) || ''}
70-
successMessageText={options.successMessageText}
71-
isRequiredLabel={options.isRequiredLabel}
72-
addScreenshotButtonLabel={options.addScreenshotButtonLabel}
73-
removeScreenshotButtonLabel={options.removeScreenshotButtonLabel}
7459
onFormClose={() => {
7560
renderContent(false);
7661
options.onFormClose && options.onFormClose();

0 commit comments

Comments
 (0)