diff --git a/packages/feedback/src/constants/index.ts b/packages/feedback/src/constants/index.ts index a8794ed663b0..2a6bc0d171aa 100644 --- a/packages/feedback/src/constants/index.ts +++ b/packages/feedback/src/constants/index.ts @@ -1,7 +1,5 @@ import { GLOBAL_OBJ } from '@sentry/utils'; -export { DEFAULT_THEME } from './theme'; - // exporting a separate copy of `WINDOW` rather than exporting the one from `@sentry/browser` // prevents the browser package from being bundled in the CDN bundle, and avoids a // circular dependency between the browser and feedback packages @@ -29,5 +27,3 @@ export const FEEDBACK_WIDGET_SOURCE = 'widget'; export const FEEDBACK_API_SOURCE = 'api'; export const SUCCESS_MESSAGE_TIMEOUT = 5000; - -export const CROP_COLOR = '#ffffff'; diff --git a/packages/feedback/src/constants/theme.ts b/packages/feedback/src/constants/theme.ts deleted file mode 100644 index ba8193afd9d0..000000000000 --- a/packages/feedback/src/constants/theme.ts +++ /dev/null @@ -1,58 +0,0 @@ -const INHERIT = 'inherit'; -const PURPLE = 'rgba(88, 74, 192, 1)'; -const PURPLE_HOVER = 'rgba(108, 95, 199, 1)'; - -export const LIGHT_THEME = { - foreground: '#2b2233', - successForeground: '#268d75', - errorForeground: '#df3338', - background: '#ffffff', - border: '1.5px solid rgba(41, 35, 47, 0.13)', - boxShadow: '0px 4px 24px 0px rgba(43, 34, 51, 0.12)', - - inputForeground: INHERIT, - inputBackground: INHERIT, - inputBackgroundHover: INHERIT, - inputBackgroundFocus: INHERIT, - inputBorder: 'var(--border)', - inputBorderRadius: '6px', - inputOutlineFocus: PURPLE_HOVER, - - buttonForeground: INHERIT, - buttonForegroundHover: INHERIT, - buttonBackground: 'var(--background)', - buttonBackgroundHover: '#f6f6f7', - buttonBorder: 'var(--border)', - buttonOutlineFocus: 'var(--input-outline-focus)', - - submitForeground: '#ffffff', - submitForegroundHover: '#ffffff', - submitBackground: PURPLE, - submitBackgroundHover: PURPLE_HOVER, - submitBorder: PURPLE_HOVER, - submitBorderRadius: 'var(--button-border-radius)', - submitOutlineFocus: '#29232f', - - triggerBackground: 'var(--background)', - triggerBackgroundHover: 'var(--button-background-hover)', - triggerBorderRadius: '1.7em/50%', - - dialogBackground: 'var(--background)', - dialogBorderRadius: '20px', -}; - -export const DEFAULT_THEME = { - light: LIGHT_THEME, - dark: { - ...LIGHT_THEME, - - foreground: '#ebe6ef', - successForeground: '#2da98c', - errorForeground: '#f55459', - background: '#29232f', - border: '1.5px solid rgba(235, 230, 239, 0.5)', - boxShadow: '0px 4px 24px 0px rgba(43, 34, 51, 0.12)', - - buttonBackgroundHover: '#352f3b', - }, -}; diff --git a/packages/feedback/src/core/components/Actor.css.ts b/packages/feedback/src/core/components/Actor.css.ts index 3daa58d09a99..60ae7cebd08e 100644 --- a/packages/feedback/src/core/components/Actor.css.ts +++ b/packages/feedback/src/core/components/Actor.css.ts @@ -23,12 +23,12 @@ export function createActorStyles(): HTMLStyleElement { line-height: 1.14em; text-decoration: none; - background-color: var(--trigger-background); - border-radius: var(--trigger-border-radius); - border: var(--border); - box-shadow: var(--box-shadow); - color: var(--foreground); - fill: var(--foreground); + background: var(--actor-background, var(--background)); + border-radius: var(--actor-border-radius, 1.7em/50%); + border: var(--actor-border, var(--border)); + box-shadow: var(--actor-box-shadow, var(--box-shadow)); + color: var(--actor-color, var(--foreground)); + fill: var(--actor-color, var(--foreground)); cursor: pointer; opacity: 1; transition: transform 0.2s ease-in-out; @@ -42,7 +42,8 @@ export function createActorStyles(): HTMLStyleElement { } .widget__actor:hover { - background-color: var(--trigger-background-hover); + background: var(--actor-hover-background, var(--background)); + filter: var(--interactive-filter); } .widget__actor svg { diff --git a/packages/feedback/src/core/createMainStyles.ts b/packages/feedback/src/core/createMainStyles.ts index b60bba37b6e3..95541ab4b06b 100644 --- a/packages/feedback/src/core/createMainStyles.ts +++ b/packages/feedback/src/core/createMainStyles.ts @@ -1,25 +1,50 @@ import type { FeedbackInternalOptions } from '@sentry/types'; import { DOCUMENT } from '../constants'; -function getThemedCssVariables(theme: FeedbackInternalOptions['themeLight']): string { +const PURPLE = 'rgba(88, 74, 192, 1)'; + +interface InternalTheme extends NonNullable { + border: string; + interactiveFilter: string; +} + +const DEFAULT_LIGHT: InternalTheme = { + foreground: '#2b2233', + background: '#ffffff', + accentForeground: 'white', + accentBackground: PURPLE, + successColor: '#268d75', + errorColor: '#df3338', + border: '1.5px solid rgba(41, 35, 47, 0.13)', + boxShadow: '0px 4px 24px 0px rgba(43, 34, 51, 0.12)', + outline: '1px auto var(--accent-background)', + interactiveFilter: 'brightness(95%)', +}; +const DEFAULT_DARK: InternalTheme = { + foreground: '#ebe6ef', + background: '#29232f', + accentForeground: 'white', + accentBackground: PURPLE, + successColor: '#2da98c', + errorColor: '#f55459', + border: '1.5px solid rgba(41, 35, 47, 0.5)', + boxShadow: '0px 4px 24px 0px rgba(43, 34, 51, 0.12)', + outline: '1px auto var(--accent-background)', + interactiveFilter: 'brightness(150%)', +}; + +function getThemedCssVariables(theme: InternalTheme): string { return ` --foreground: ${theme.foreground}; - --success-foreground: ${theme.successForeground}; - --error-foreground: ${theme.errorForeground}; --background: ${theme.background}; + --accent-foreground: ${theme.accentForeground}; + --accent-background: ${theme.accentBackground}; + --success-color: ${theme.successColor}; + --error-color: ${theme.errorColor}; --border: ${theme.border}; --box-shadow: ${theme.boxShadow}; - - --button-foreground: ${theme.buttonForeground}; - --button-foreground-hover: ${theme.buttonForegroundHover}; - --button-background: ${theme.buttonBackground}; - --button-background-hover: ${theme.buttonBackgroundHover}; - --button-border: ${theme.buttonBorder}; - --button-outline-focus: ${theme.buttonOutlineFocus}; - - --trigger-background: ${theme.triggerBackground}; - --trigger-background-hover: ${theme.triggerBackgroundHover}; - --trigger-border-radius: ${theme.triggerBorderRadius}; + --outline: ${theme.outline}; + --interactive-filter: ${theme.interactiveFilter}; `; } @@ -41,7 +66,9 @@ export function createMainStyles({ colorScheme, themeDark, themeLight }: Feedbac font-family: var(--font-family); font-size: var(--font-size); - ${getThemedCssVariables(colorScheme === 'dark' ? themeDark : themeLight)} + ${getThemedCssVariables( + colorScheme === 'dark' ? { ...DEFAULT_DARK, ...themeDark } : { ...DEFAULT_LIGHT, ...themeLight }, + )} } ${ @@ -49,7 +76,7 @@ ${ ? ` @media (prefers-color-scheme: dark) { :host { - ${getThemedCssVariables(themeDark)} + ${getThemedCssVariables({ ...DEFAULT_DARK, ...themeDark })} } }` : '' diff --git a/packages/feedback/src/core/integration.ts b/packages/feedback/src/core/integration.ts index 9247f36b6990..61c8a83ef016 100644 --- a/packages/feedback/src/core/integration.ts +++ b/packages/feedback/src/core/integration.ts @@ -12,7 +12,6 @@ import { ADD_SCREENSHOT_LABEL, CANCEL_BUTTON_LABEL, CONFIRM_BUTTON_LABEL, - DEFAULT_THEME, DOCUMENT, EMAIL_LABEL, EMAIL_PLACEHOLDER, @@ -79,8 +78,8 @@ export const buildFeedbackIntegration = ({ // FeedbackThemeConfiguration colorScheme = 'system', - themeLight, - themeDark, + themeLight = {}, + themeDark = {}, // FeedbackTextConfiguration addScreenshotButtonLabel = ADD_SCREENSHOT_LABEL, @@ -118,14 +117,8 @@ export const buildFeedbackIntegration = ({ useSentryUser, colorScheme, - themeDark: { - ...DEFAULT_THEME.dark, - ...themeDark, - }, - themeLight: { - ...DEFAULT_THEME.light, - ...themeLight, - }, + themeDark, + themeLight, triggerLabel, cancelButtonLabel, diff --git a/packages/feedback/src/modal/components/Dialog.css.ts b/packages/feedback/src/modal/components/Dialog.css.ts index 8e280e6df4da..ddcd90184657 100644 --- a/packages/feedback/src/modal/components/Dialog.css.ts +++ b/packages/feedback/src/modal/components/Dialog.css.ts @@ -1,4 +1,3 @@ -import type { FeedbackInternalOptions } from '@sentry/types'; import { DOCUMENT } from '../../constants'; const DIALOG = ` @@ -15,8 +14,8 @@ const DIALOG = ` height: 100vh; width: 100vw; - color: var(--foreground); - fill: var(--foreground); + color: var(--dialog-color, var(--foreground)); + fill: var(--dialog-color, var(--foreground)); line-height: 1.75em; background-color: rgba(0, 0, 0, 0.05); @@ -59,16 +58,16 @@ const DIALOG = ` display: flex; flex-direction: column; gap: 16px; - padding: var(--dialog-padding); + padding: var(--dialog-padding, 24px); max-width: 100%; width: 100%; max-height: 100%; overflow: auto; - background-color: var(--dialog-background); - border-radius: var(--dialog-border-radius); - border: var(--border); - box-shadow: var(--box-shadow); + background: var(--dialog-background, var(--background)); + border-radius: var(--dialog-border-radius, 20px); + border: var(--dialog-border, var(--border)); + box-shadow: var(--dialog-box-shadow, var(--box-shadow)); transform: translate(0, 0) scale(1); transition: transform 0.2s ease-in-out; } @@ -79,7 +78,7 @@ const DIALOG_HEADER = ` display: flex; align-items: center; justify-content: space-between; - font-weight: 600; + font-weight: var(--dialog-header-weight, 600); margin: 0; } @@ -87,7 +86,7 @@ const DIALOG_HEADER = ` display: inline-flex; } .brand-link:focus-visible { - outline: 1px auto var(--input-outline-focus); + outline: var(--outline); } `; @@ -101,7 +100,7 @@ const FORM = ` } .form__right { - width: 272px; + width: var(--form-width, 272px); display: flex; overflow: auto; flex-direction: column; @@ -147,24 +146,25 @@ const FORM = ` .form__input { font-family: inherit; line-height: inherit; - background-color: var(--input-background); + background: transparent; box-sizing: border-box; - border: var(--input-border); - border-radius: var(--input-border-radius); - color: var(--input-foreground); - fill: var(--input-foreground); - font-size: var(--font-size); - font-weight: 500; + border: var(--input-border, var(--border)); + border-radius: var(--input-border-radius, 6px); + color: var(--input-color, inherit); + fill: var(--input-color, inherit); + font-size: var(--input-font-size, inherit); + font-weight: var(--input-font-weight, 500); padding: 6px 12px; } .form__input::placeholder { - color: var(--input-foreground); opacity: 0.65; + color: var(--input-placeholder-color, inherit); + filter: var(--interactive-filter); } .form__input:focus-visible { - outline: 1px auto var(--input-outline-focus); + outline: var(--input-focus-outline, var(--outline)); } .form__input--textarea { @@ -173,8 +173,8 @@ const FORM = ` } .error { - color: var(--error-foreground); - fill: var(--error-foreground); + color: var(--error-color); + fill: var(--error-color); } `; @@ -186,13 +186,13 @@ const BUTTON = ` .btn { line-height: inherit; - border: var(--cancel-border); - border-radius: var(--form-content-border-radius); + border: var(--button-border, var(--border)); + border-radius: var(--button-border-radius, 6px); cursor: pointer; font-family: inherit; - font-size: var(--font-size); - font-weight: 600; - padding: 6px 16px; + font-size: var(--button-font-size, inherit); + font-weight: var(--button-font-weight, 600); + padding: var(--button-padding, 6px 16px); } .btn[disabled] { opacity: 0.6; @@ -200,37 +200,43 @@ const BUTTON = ` } .btn--primary { - color: var(--submit-foreground); - fill: var(--submit-foreground); - background-color: var(--submit-background); - border: var(--submit-border); - border-radius: var(--input-border-radius); - font-weight: 500; + color: var(--button-primary-color, var(--accent-foreground)); + fill: var(--button-primary-color, var(--accent-foreground)); + background: var(--button-primary-background, var(--accent-background)); + border: var(--button-primary-border, var(--border)); + border-radius: var(--button-primary-border-radius, 6px); + font-weight: var(--button-primary-font-weight, 500); } .btn--primary:hover { - color: var(--submit-foreground-hover); - fill: var(--submit-foreground-hover); - background-color: var(--submit-background-hover); + color: var(--button-primary-hover-color, var(--accent-foreground)); + fill: var(--button-primary-hover-color, var(--accent-foreground)); + background: var(--button-primary-hover-background, var(--accent-background)); + filter: var(--interactive-filter); } .btn--primary:focus-visible { - outline: 1px auto var(--submit-outline-focus); + background: var(--button-primary-hover-background, var(--accent-background)); + filter: var(--interactive-filter); + outline: var(--button-primary-focus-outline, var(--outline)); } .btn--default { - color: var(--button-foreground); - fill: var(--button-foreground); - background-color: var(--button-background); - border: var(--button-border); - border-radius: var(--input-border-radius); - font-weight: 500; + color: var(--button-color, var(--foreground)); + fill: var(--button-color, var(--foreground)); + background: var(--button-background, var(--background)); + border: var(--button-border, var(--border)); + border-radius: var(--button-border-radius, 6px); + font-weight: var(--button-font-weight, 500); } .btn--default:hover { - color: var(--button-foreground-hover); - fill: var(--button-foreground-hover); - background-color: var(--button-background-hover); + color: var(--button-color, var(--foreground)); + fill: var(--button-color, var(--foreground)); + background: var(--button-hover-background, var(--background)); + filter: var(--interactive-filter); } .btn--default:focus-visible { - outline: 1px auto var(--button-outline-focus); + background: var(--button-hover-background, var(--background)); + filter: var(--interactive-filter); + outline: var(--button-focus-outline, var(--outline)); } `; @@ -242,15 +248,16 @@ const SUCCESS = ` z-index: var(--z-index); } .success__content { - background-color: var(--trigger-background); - border: var(--border); - border-radius: var(--trigger-border-radius); - box-shadow: var(--box-shadow); - font-weight: 600; - color: var(--success-foreground); - fill: var(--success-foreground); + background: var(--success-background, var(--background)); + border: var(--success-border, var(--border)); + border-radius: var(--success-border-radius, 1.7em/50%); + box-shadow: var(--success-box-shadow, var(--box-shadow)); + font-weight: var(--success-font-weight, 600); + color: var(--success-color); + fill: var(--success-color); padding: 12px 24px; - line-height: 25px; + line-height: 1.75em; + display: grid; align-items: center; grid-auto-flow: column; @@ -263,51 +270,15 @@ const SUCCESS = ` } `; -function getThemedCssVariables(theme: FeedbackInternalOptions['themeLight']): string { - return ` - --input-border-radius: ${theme.inputBorderRadius}; - --input-background: ${theme.inputBackground}; - --input-background-hover: ${theme.inputBackgroundHover}; - --input-background-focus: ${theme.inputBackgroundFocus}; - --input-foreground: ${theme.inputForeground}; - --input-border: ${theme.inputBorder}; - --input-outline-focus: ${theme.inputOutlineFocus}; - - --submit-foreground: ${theme.submitForeground}; - --submit-foreground-hover: ${theme.submitForegroundHover}; - --submit-background: ${theme.submitBackground}; - --submit-background-hover: ${theme.submitBackgroundHover}; - --submit-border: ${theme.submitBorder}; - --submit-outline-focus: ${theme.submitOutlineFocus}; - - --dialog-background: ${theme.dialogBackground}; - --dialog-border-radius: ${theme.dialogBorderRadius}; - `; -} - /** * Creates