diff --git a/apps/web/app/(app)/(onboarding)/workspaces/[workspaceId]/xm-templates/lib/utils.test.ts b/apps/web/app/(app)/(onboarding)/workspaces/[workspaceId]/xm-templates/lib/utils.test.ts index b13066e1a8..e372220282 100644 --- a/apps/web/app/(app)/(onboarding)/workspaces/[workspaceId]/xm-templates/lib/utils.test.ts +++ b/apps/web/app/(app)/(onboarding)/workspaces/[workspaceId]/xm-templates/lib/utils.test.ts @@ -60,8 +60,8 @@ const mockTemplate: TXMTemplate = { ], styling: { brandColor: { light: "#0000FF" }, - questionColor: { light: "#00FF00" }, - inputColor: { light: "#FF0000" }, + elementHeadlineColor: { light: "#00FF00" }, + inputBgColor: { light: "#FF0000" }, }, }; diff --git a/apps/web/lib/styling/constants.ts b/apps/web/lib/styling/constants.ts index 7b5deffc37..eee0166f8b 100644 --- a/apps/web/lib/styling/constants.ts +++ b/apps/web/lib/styling/constants.ts @@ -4,8 +4,8 @@ import { isLight, mixColor } from "@/lib/utils/colors"; export const COLOR_DEFAULTS = { brandColor: "#64748b", - questionColor: "#2b2524", - inputColor: "#ffffff", + elementHeadlineColor: "#2b2524", + inputBgColor: "#ffffff", inputBorderColor: "#cbd5e1", cardBackgroundColor: "#ffffff", cardBorderColor: "#f8fafc", @@ -40,10 +40,8 @@ export const getSuggestedColors = (brandColor: string = DEFAULT_BRAND_COLOR) => return { // General "brandColor.light": brandColor, - "questionColor.light": questionColor, - // Headlines & Descriptions — use questionColor to match the legacy behaviour - // where all text elements derived their color from questionColor. + // Headlines & Descriptions "elementHeadlineColor.light": questionColor, "elementDescriptionColor.light": questionColor, "elementUpperLabelColor.light": questionColor, @@ -53,7 +51,7 @@ export const getSuggestedColors = (brandColor: string = DEFAULT_BRAND_COLOR) => "buttonTextColor.light": isLight(brandColor) ? "#0f172a" : "#ffffff", // Inputs - "inputColor.light": inputBg, + "inputBgColor.light": inputBg, "inputBorderColor.light": inputBorder, "inputTextColor.light": questionColor, @@ -94,8 +92,6 @@ const _colors = getSuggestedColors(DEFAULT_BRAND_COLOR); export const STYLE_DEFAULTS: TWorkspaceStyling = { allowStyleOverwrite: true, brandColor: { light: _colors["brandColor.light"] }, - questionColor: { light: _colors["questionColor.light"] }, - inputColor: { light: _colors["inputColor.light"] }, inputBorderColor: { light: _colors["inputBorderColor.light"] }, cardBackgroundColor: { light: _colors["cardBackgroundColor.light"] }, cardBorderColor: { light: _colors["cardBorderColor.light"] }, @@ -117,6 +113,7 @@ export const STYLE_DEFAULTS: TWorkspaceStyling = { elementUpperLabelFontWeight: 400, // Inputs + inputBgColor: { light: _colors["inputBgColor.light"] }, inputTextColor: { light: _colors["inputTextColor.light"] }, inputBorderRadius: 8, inputHeight: 20, @@ -151,43 +148,6 @@ export const STYLE_DEFAULTS: TWorkspaceStyling = { progressIndicatorBgColor: { light: _colors["progressIndicatorBgColor.light"] }, }; -/** - * Fills in new v4.7 color fields from legacy v4.6 fields when they are missing. - * - * v4.6 stored: brandColor, questionColor, inputColor, inputBorderColor. - * v4.7 adds: elementHeadlineColor, buttonBgColor, optionBgColor, etc. - * - * When loading v4.6 data the new fields are absent. Without this helper the - * form would fall back to STYLE_DEFAULTS (derived from the *default* brand - * colour), causing a visible mismatch. This function derives the new fields - * from the actually-saved legacy fields so the preview and form stay coherent. - * - * Only sets a field when the legacy source exists AND the new field is absent. - */ -export const deriveNewFieldsFromLegacy = (saved: Record): Record => { - const light = (key: string): string | undefined => - (saved[key] as { light?: string } | null | undefined)?.light; - - const q = light("questionColor"); - const b = light("brandColor"); - const i = light("inputColor"); - const inputBorder = light("inputBorderColor"); - - return { - ...(q && !saved.elementHeadlineColor && { elementHeadlineColor: { light: q } }), - ...(q && !saved.elementDescriptionColor && { elementDescriptionColor: { light: q } }), - ...(q && !saved.elementUpperLabelColor && { elementUpperLabelColor: { light: q } }), - ...(q && !saved.inputTextColor && { inputTextColor: { light: q } }), - ...(q && !saved.optionLabelColor && { optionLabelColor: { light: q } }), - ...(b && !saved.buttonBgColor && { buttonBgColor: { light: b } }), - ...(b && !saved.buttonTextColor && { buttonTextColor: { light: isLight(b) ? "#0f172a" : "#ffffff" } }), - ...(i && !saved.optionBgColor && { optionBgColor: { light: i } }), - ...(inputBorder && !saved.optionBorderColor && { optionBorderColor: { light: inputBorder } }), - ...(b && !saved.progressIndicatorBgColor && { progressIndicatorBgColor: { light: b } }), - ...(b && !saved.progressTrackBgColor && { progressTrackBgColor: { light: mixColor(b, "#ffffff", 0.8) } }), - }; -}; - /** * Builds a complete TWorkspaceStyling object from a single brand color. * @@ -203,13 +163,12 @@ export const buildStylingFromBrandColor = (brandColor: string = DEFAULT_BRAND_CO return { ...STYLE_DEFAULTS, brandColor: { light: colors["brandColor.light"] }, - questionColor: { light: colors["questionColor.light"] }, elementHeadlineColor: { light: colors["elementHeadlineColor.light"] }, elementDescriptionColor: { light: colors["elementDescriptionColor.light"] }, elementUpperLabelColor: { light: colors["elementUpperLabelColor.light"] }, buttonBgColor: { light: colors["buttonBgColor.light"] }, buttonTextColor: { light: colors["buttonTextColor.light"] }, - inputColor: { light: colors["inputColor.light"] }, + inputBgColor: { light: colors["inputBgColor.light"] }, inputBorderColor: { light: colors["inputBorderColor.light"] }, inputTextColor: { light: colors["inputTextColor.light"] }, optionBgColor: { light: colors["optionBgColor.light"] }, diff --git a/apps/web/modules/ee/whitelabel/remove-branding/lib/workspace.test.ts b/apps/web/modules/ee/whitelabel/remove-branding/lib/workspace.test.ts index cd6aa7b447..a0b20100ce 100644 --- a/apps/web/modules/ee/whitelabel/remove-branding/lib/workspace.test.ts +++ b/apps/web/modules/ee/whitelabel/remove-branding/lib/workspace.test.ts @@ -36,8 +36,6 @@ describe("updateWorkspaceBranding", () => { styling: { allowStyleOverwrite: true, brandColor: { light: "#64748b" }, - questionColor: { light: "#2b2524" }, - inputColor: { light: "#ffffff" }, inputBorderColor: { light: "#cbd5e1" }, cardBackgroundColor: { light: "#ffffff" }, cardBorderColor: { light: "#f8fafc" }, diff --git a/apps/web/modules/email/components/preview-email-template.tsx b/apps/web/modules/email/components/preview-email-template.tsx index 00093612f8..18b114c3eb 100644 --- a/apps/web/modules/email/components/preview-email-template.tsx +++ b/apps/web/modules/email/components/preview-email-template.tsx @@ -455,10 +455,10 @@ function EmailTemplateWrapper({ const colors = { "brand-color": styling.brandColor?.light ?? COLOR_DEFAULTS.brandColor, "card-bg-color": styling.cardBackgroundColor?.light ?? COLOR_DEFAULTS.cardBackgroundColor, - "input-color": styling.inputColor?.light ?? COLOR_DEFAULTS.inputColor, + "input-color": styling.inputBgColor?.light ?? COLOR_DEFAULTS.inputBgColor, "input-border-color": styling.inputBorderColor?.light ?? COLOR_DEFAULTS.inputBorderColor, "card-border-color": styling.cardBorderColor?.light ?? COLOR_DEFAULTS.cardBorderColor, - "question-color": styling.questionColor?.light ?? COLOR_DEFAULTS.questionColor, + "question-color": styling.elementHeadlineColor?.light ?? COLOR_DEFAULTS.elementHeadlineColor, }; if (isLight(colors["question-color"])) { diff --git a/apps/web/modules/survey/editor/components/form-styling-settings.tsx b/apps/web/modules/survey/editor/components/form-styling-settings.tsx index 6ad221a8cc..59279d6f7e 100644 --- a/apps/web/modules/survey/editor/components/form-styling-settings.tsx +++ b/apps/web/modules/survey/editor/components/form-styling-settings.tsx @@ -181,7 +181,7 @@ export const FormStylingSettings = ({
diff --git a/apps/web/modules/survey/editor/components/styling-view.tsx b/apps/web/modules/survey/editor/components/styling-view.tsx index c66589f9c1..4bef37e23a 100644 --- a/apps/web/modules/survey/editor/components/styling-view.tsx +++ b/apps/web/modules/survey/editor/components/styling-view.tsx @@ -9,12 +9,7 @@ import toast from "react-hot-toast"; import { useTranslation } from "react-i18next"; import { TSurvey, TSurveyStyling } from "@formbricks/types/surveys/types"; import { TWorkspaceStyling } from "@formbricks/types/workspace"; -import { - COLOR_DEFAULTS, - STYLE_DEFAULTS, - deriveNewFieldsFromLegacy, - getSuggestedColors, -} from "@/lib/styling/constants"; +import { COLOR_DEFAULTS, STYLE_DEFAULTS, getSuggestedColors } from "@/lib/styling/constants"; import { FormStylingSettings } from "@/modules/survey/editor/components/form-styling-settings"; import { LogoSettingsCard } from "@/modules/survey/editor/components/logo-settings-card"; import { AlertDialog } from "@/modules/ui/components/alert-dialog"; @@ -73,15 +68,10 @@ export const StylingView = ({ ? Object.fromEntries(Object.entries(localSurvey.styling).filter(([, v]) => v != null)) : {}; - const workspaceLegacyFills = deriveNewFieldsFromLegacy(cleanWorkspace); - const surveyLegacyFills = deriveNewFieldsFromLegacy(cleanSurvey); - const form = useForm({ defaultValues: { ...STYLE_DEFAULTS, - ...workspaceLegacyFills, ...cleanWorkspace, - ...surveyLegacyFills, ...cleanSurvey, }, }); diff --git a/apps/web/modules/workspaces/settings/look/components/theme-styling.tsx b/apps/web/modules/workspaces/settings/look/components/theme-styling.tsx index 7715235734..9c226e34eb 100644 --- a/apps/web/modules/workspaces/settings/look/components/theme-styling.tsx +++ b/apps/web/modules/workspaces/settings/look/components/theme-styling.tsx @@ -11,12 +11,7 @@ import { TSurveyStyling, TSurveyType } from "@formbricks/types/surveys/types"; import { TWorkspace } from "@formbricks/types/workspace"; import { TWorkspaceStyling, ZWorkspaceStyling } from "@formbricks/types/workspace"; import { previewSurvey } from "@/app/lib/templates"; -import { - COLOR_DEFAULTS, - STYLE_DEFAULTS, - deriveNewFieldsFromLegacy, - getSuggestedColors, -} from "@/lib/styling/constants"; +import { COLOR_DEFAULTS, STYLE_DEFAULTS, getSuggestedColors } from "@/lib/styling/constants"; import { getFormattedErrorMessage } from "@/lib/utils/helper"; import { FormStylingSettings } from "@/modules/survey/editor/components/form-styling-settings"; import { Alert, AlertDescription } from "@/modules/ui/components/alert"; @@ -67,10 +62,8 @@ export const ThemeStyling = ({ ? Object.fromEntries(Object.entries(savedStyling).filter(([, v]) => v != null)) : {}; - const legacyFills = deriveNewFieldsFromLegacy(cleanSaved); - const form = useForm({ - defaultValues: { ...STYLE_DEFAULTS, ...legacyFills, ...cleanSaved }, + defaultValues: { ...STYLE_DEFAULTS, ...cleanSaved }, resolver: zodResolver(ZWorkspaceStyling), }); diff --git a/docs/api-v2-reference/openapi.yml b/docs/api-v2-reference/openapi.yml index abbe07a859..9d52de3956 100644 --- a/docs/api-v2-reference/openapi.yml +++ b/docs/api-v2-reference/openapi.yml @@ -5566,36 +5566,6 @@ components: pattern: ^#(?:[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$ required: - light - questionColor: - type: - - object - - "null" - properties: - light: - type: string - pattern: ^#(?:[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$ - dark: - type: - - string - - "null" - pattern: ^#(?:[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$ - required: - - light - inputColor: - type: - - object - - "null" - properties: - light: - type: string - pattern: ^#(?:[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$ - dark: - type: - - string - - "null" - pattern: ^#(?:[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$ - required: - - light inputBorderColor: type: - object diff --git a/packages/database/migration/20260420000000_migrate_legacy_styling_fields/migration.sql b/packages/database/migration/20260420000000_migrate_legacy_styling_fields/migration.sql new file mode 100644 index 0000000000..2e303ea7c2 --- /dev/null +++ b/packages/database/migration/20260420000000_migrate_legacy_styling_fields/migration.sql @@ -0,0 +1,74 @@ +-- Migrate legacy styling fields (questionColor, inputColor) to granular fields +-- and remove the legacy keys from the JSONB. +-- +-- Mapping: +-- questionColor -> elementHeadlineColor, elementDescriptionColor, +-- elementUpperLabelColor, inputTextColor, optionLabelColor +-- brandColor -> buttonBgColor, progressIndicatorBgColor (brandColor itself is kept) +-- inputColor -> optionBgColor, inputBgColor +-- inputBorderColor -> optionBorderColor (inputBorderColor itself is kept) + +-- ── Workspace ──────────────────────────────────────────────────────────────── +-- NOTE: We use COALESCE(styling->'field', 'null'::jsonb) = 'null'::jsonb instead of +-- NOT (styling ? 'field') to treat JSON null values as absent — the form layer saves +-- null to mean "use default", so the migration must copy the legacy value in that case too. +UPDATE "Workspace" +SET styling = ( + styling + -- questionColor → five text/label fields + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'elementHeadlineColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('elementHeadlineColor', styling->'questionColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'elementDescriptionColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('elementDescriptionColor', styling->'questionColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'elementUpperLabelColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('elementUpperLabelColor', styling->'questionColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'inputTextColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('inputTextColor', styling->'questionColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'optionLabelColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('optionLabelColor', styling->'questionColor') ELSE '{}'::jsonb END + -- brandColor → button + progress indicator + || CASE WHEN styling ? 'brandColor' AND COALESCE(styling->'buttonBgColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('buttonBgColor', styling->'brandColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'brandColor' AND COALESCE(styling->'progressIndicatorBgColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('progressIndicatorBgColor', styling->'brandColor') ELSE '{}'::jsonb END + -- inputColor → option + input background + || CASE WHEN styling ? 'inputColor' AND COALESCE(styling->'optionBgColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('optionBgColor', styling->'inputColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'inputColor' AND COALESCE(styling->'inputBgColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('inputBgColor', styling->'inputColor') ELSE '{}'::jsonb END + -- inputBorderColor → optionBorderColor + || CASE WHEN styling ? 'inputBorderColor' AND COALESCE(styling->'optionBorderColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('optionBorderColor', styling->'inputBorderColor') ELSE '{}'::jsonb END +) - 'questionColor' - 'inputColor' +WHERE styling IS NOT NULL + AND styling != 'null'::jsonb + AND jsonb_typeof(styling) = 'object'; + +-- ── Survey ─────────────────────────────────────────────────────────────────── +UPDATE "Survey" +SET styling = ( + styling + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'elementHeadlineColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('elementHeadlineColor', styling->'questionColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'elementDescriptionColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('elementDescriptionColor', styling->'questionColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'elementUpperLabelColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('elementUpperLabelColor', styling->'questionColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'inputTextColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('inputTextColor', styling->'questionColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'questionColor' AND COALESCE(styling->'optionLabelColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('optionLabelColor', styling->'questionColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'brandColor' AND COALESCE(styling->'buttonBgColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('buttonBgColor', styling->'brandColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'brandColor' AND COALESCE(styling->'progressIndicatorBgColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('progressIndicatorBgColor', styling->'brandColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'inputColor' AND COALESCE(styling->'optionBgColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('optionBgColor', styling->'inputColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'inputColor' AND COALESCE(styling->'inputBgColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('inputBgColor', styling->'inputColor') ELSE '{}'::jsonb END + || CASE WHEN styling ? 'inputBorderColor' AND COALESCE(styling->'optionBorderColor', 'null'::jsonb) = 'null'::jsonb + THEN jsonb_build_object('optionBorderColor', styling->'inputBorderColor') ELSE '{}'::jsonb END +) - 'questionColor' - 'inputColor' +WHERE styling IS NOT NULL + AND styling != 'null'::jsonb + AND jsonb_typeof(styling) = 'object'; diff --git a/packages/database/zod/surveys.ts b/packages/database/zod/surveys.ts index dd8ea4333f..e238e1dacb 100644 --- a/packages/database/zod/surveys.ts +++ b/packages/database/zod/surveys.ts @@ -114,8 +114,6 @@ const ZSurveyBase = z.object({ styling: z .object({ brandColor: ZStylingColor.nullish(), - questionColor: ZStylingColor.nullish(), - inputColor: ZStylingColor.nullish(), inputBorderColor: ZStylingColor.nullish(), cardBackgroundColor: ZStylingColor.nullish(), cardBorderColor: ZStylingColor.nullish(), diff --git a/packages/js-core/src/types/config.ts b/packages/js-core/src/types/config.ts index 4cf584cb42..19059413c2 100644 --- a/packages/js-core/src/types/config.ts +++ b/packages/js-core/src/types/config.ts @@ -96,16 +96,66 @@ export interface TStylingColor { dark?: string | null | undefined; } +type TDimension = number | string | null; + export interface TBaseStyling { brandColor?: TStylingColor | null; - questionColor?: TStylingColor | null; - inputColor?: TStylingColor | null; + accentBgColor?: TStylingColor | null; + accentBgColorSelected?: TStylingColor | null; + fontFamily?: string | null; + + // Buttons + buttonBgColor?: TStylingColor | null; + buttonTextColor?: TStylingColor | null; + buttonBorderRadius?: TDimension; + buttonHeight?: TDimension; + buttonFontSize?: TDimension; + buttonFontWeight?: TDimension; + buttonPaddingX?: TDimension; + buttonPaddingY?: TDimension; + + // Inputs + inputBgColor?: TStylingColor | null; inputBorderColor?: TStylingColor | null; + inputBorderRadius?: TDimension; + inputHeight?: TDimension; + inputTextColor?: TStylingColor | null; + inputFontSize?: TDimension; + inputPlaceholderOpacity?: number | null; + inputPaddingX?: TDimension; + inputPaddingY?: TDimension; + inputShadow?: string | null; + + // Options + optionBgColor?: TStylingColor | null; + optionLabelColor?: TStylingColor | null; + optionBorderColor?: TStylingColor | null; + optionBorderRadius?: TDimension; + optionPaddingX?: TDimension; + optionPaddingY?: TDimension; + optionFontSize?: TDimension; + + // Headlines & Descriptions + elementHeadlineFontSize?: TDimension; + elementHeadlineFontWeight?: TDimension; + elementHeadlineColor?: TStylingColor | null; + elementDescriptionFontSize?: TDimension; + elementDescriptionFontWeight?: TDimension; + elementDescriptionColor?: TStylingColor | null; + elementUpperLabelFontSize?: TDimension; + elementUpperLabelColor?: TStylingColor | null; + elementUpperLabelFontWeight?: TDimension; + + // Progress Bar + progressTrackHeight?: TDimension; + progressTrackBgColor?: TStylingColor | null; + progressIndicatorBgColor?: TStylingColor | null; + cardBackgroundColor?: TStylingColor | null; cardBorderColor?: TStylingColor | null; highlightBorderColor?: TStylingColor | null; isDarkModeEnabled?: boolean | null; - roundness?: number | null; + roundness?: TDimension; cardArrangement?: { linkSurveys: "casual" | "straight" | "simple"; appSurveys: "casual" | "straight" | "simple"; diff --git a/packages/survey-ui/src/components/elements/consent.stories.tsx b/packages/survey-ui/src/components/elements/consent.stories.tsx index ecc0e8288f..26d36cd742 100644 --- a/packages/survey-ui/src/components/elements/consent.stories.tsx +++ b/packages/survey-ui/src/components/elements/consent.stories.tsx @@ -59,7 +59,7 @@ export const StylingPlayground: Story = { ...pickArgTypes(inputStylingArgTypes, [ "inputBgColor", "inputBorderColor", - "inputColor", + "inputTextColor", "inputFontSize", "inputFontWeight", "inputWidth", diff --git a/packages/survey-ui/src/components/elements/date.stories.tsx b/packages/survey-ui/src/components/elements/date.stories.tsx index 1392629b22..09f4654afd 100644 --- a/packages/survey-ui/src/components/elements/date.stories.tsx +++ b/packages/survey-ui/src/components/elements/date.stories.tsx @@ -90,7 +90,7 @@ export const StylingPlayground: Story = { control: "color", table: { category: "Input Styling" }, }, - inputColor: { + inputTextColor: { control: "color", table: { category: "Input Styling" }, }, diff --git a/packages/survey-ui/src/components/elements/file-upload.stories.tsx b/packages/survey-ui/src/components/elements/file-upload.stories.tsx index 6fd3f8db65..d068023a66 100644 --- a/packages/survey-ui/src/components/elements/file-upload.stories.tsx +++ b/packages/survey-ui/src/components/elements/file-upload.stories.tsx @@ -50,7 +50,7 @@ const meta: Meta = { ...pickArgTypes(inputStylingArgTypes, [ "inputBgColor", "inputBorderColor", - "inputColor", + "inputTextColor", "inputFontSize", "inputFontWeight", "inputWidth", diff --git a/packages/survey-ui/src/components/elements/form-field.stories.tsx b/packages/survey-ui/src/components/elements/form-field.stories.tsx index d28f455658..1756904e00 100644 --- a/packages/survey-ui/src/components/elements/form-field.stories.tsx +++ b/packages/survey-ui/src/components/elements/form-field.stories.tsx @@ -154,7 +154,7 @@ export const StylingPlayground: Story = { control: "text", table: { category: "Input Styling" }, }, - inputColor: { + inputTextColor: { control: "color", table: { category: "Input Styling" }, }, diff --git a/packages/survey-ui/src/components/elements/nps.stories.tsx b/packages/survey-ui/src/components/elements/nps.stories.tsx index 98fc5eb014..1121e4d5e9 100644 --- a/packages/survey-ui/src/components/elements/nps.stories.tsx +++ b/packages/survey-ui/src/components/elements/nps.stories.tsx @@ -72,7 +72,7 @@ export const StylingPlayground: Story = { ...pickArgTypes(inputStylingArgTypes, [ "inputBgColor", "inputBorderColor", - "inputColor", + "inputTextColor", "inputFontWeight", "inputBorderRadius", ]), diff --git a/packages/survey-ui/src/components/elements/open-text.stories.tsx b/packages/survey-ui/src/components/elements/open-text.stories.tsx index dcb8dbe4a2..3abc63d41d 100644 --- a/packages/survey-ui/src/components/elements/open-text.stories.tsx +++ b/packages/survey-ui/src/components/elements/open-text.stories.tsx @@ -80,7 +80,7 @@ export const StylingPlayground: Story = { ...pickArgTypes(inputStylingArgTypes, [ "inputBgColor", "inputBorderColor", - "inputColor", + "inputTextColor", "inputFontSize", "inputFontWeight", "inputWidth", diff --git a/packages/survey-ui/src/components/elements/rating.stories.tsx b/packages/survey-ui/src/components/elements/rating.stories.tsx index dd07193231..40bde26806 100644 --- a/packages/survey-ui/src/components/elements/rating.stories.tsx +++ b/packages/survey-ui/src/components/elements/rating.stories.tsx @@ -100,7 +100,7 @@ export const StylingPlayground: Story = { ...pickArgTypes(inputStylingArgTypes, [ "inputBgColor", "inputBorderColor", - "inputColor", + "inputTextColor", "inputFontWeight", "inputBorderRadius", ]), diff --git a/packages/survey-ui/src/components/general/input.stories.tsx b/packages/survey-ui/src/components/general/input.stories.tsx index 96a9e895ff..8fd219901c 100644 --- a/packages/survey-ui/src/components/general/input.stories.tsx +++ b/packages/survey-ui/src/components/general/input.stories.tsx @@ -12,7 +12,7 @@ interface StylingOptions { inputFontFamily: string; inputFontSize: string; inputFontWeight: string; - inputColor: string; + inputTextColor: string; inputPlaceholderColor: string; inputPaddingX: string; inputPaddingY: string; @@ -74,7 +74,7 @@ const withCSSVariables: Decorator = ( inputFontFamily, inputFontSize, inputFontWeight, - inputColor, + inputTextColor, inputPlaceholderColor, inputPaddingX, inputPaddingY, @@ -91,7 +91,7 @@ const withCSSVariables: Decorator = ( "--fb-input-font-family": inputFontFamily, "--fb-input-font-size": inputFontSize, "--fb-input-font-weight": inputFontWeight, - "--fb-input-color": inputColor, + "--fb-input-text-color": inputTextColor, "--fb-input-placeholder-color": inputPlaceholderColor, "--fb-input-padding-x": inputPaddingX, "--fb-input-padding-y": inputPaddingY, @@ -168,7 +168,7 @@ export const StylingPlayground: Story = { defaultValue: { summary: "400" }, }, }, - inputColor: { + inputTextColor: { control: "color", table: { category: "Input Styling", diff --git a/packages/survey-ui/src/lib/story-helpers.tsx b/packages/survey-ui/src/lib/story-helpers.tsx index 6f5d1b7f7e..49a3795923 100644 --- a/packages/survey-ui/src/lib/story-helpers.tsx +++ b/packages/survey-ui/src/lib/story-helpers.tsx @@ -18,7 +18,7 @@ export interface BaseStylingOptions { // Input styling inputBgColor: string; inputBorderColor: string; - inputColor: string; + inputTextColor: string; inputFontSize: string; inputFontWeight: string; // Survey styling @@ -178,7 +178,7 @@ export const inputStylingArgTypes = { control: "color", table: { category: "Input Styling" }, }, - inputColor: { + inputTextColor: { control: "color", table: { category: "Input Styling" }, }, @@ -337,7 +337,7 @@ const CSS_VAR_MAP: CSSVarMapping = { elementDescriptionColor: "--fb-element-description-color", inputBgColor: "--fb-input-bg-color", inputBorderColor: "--fb-input-border-color", - inputColor: "--fb-input-color", + inputTextColor: "--fb-input-text-color", inputFontSize: "--fb-input-font-size", inputFontWeight: "--fb-input-font-weight", inputWidth: "--fb-input-width", diff --git a/packages/surveys/src/components/general/survey.tsx b/packages/surveys/src/components/general/survey.tsx index 2f98cb0189..ff91ffb83a 100644 --- a/packages/surveys/src/components/general/survey.tsx +++ b/packages/surveys/src/components/general/survey.tsx @@ -1179,7 +1179,7 @@ export function Survey({ survey={localSurvey} surveyLanguages={localSurvey.languages} setSelectedLanguageCode={setSelectedLanguage} - hoverColor={styling.inputColor?.light ?? "#f8fafc"} + hoverColor={styling.inputBgColor?.light ?? "#f8fafc"} borderRadius={styling.roundness ?? 8} setDir={setDir} dir={dir} @@ -1192,7 +1192,7 @@ export function Survey({ {isCloseButtonVisible && ( )} diff --git a/packages/surveys/src/lib/styles.test.ts b/packages/surveys/src/lib/styles.test.ts index b04756e2b1..72bb16c855 100644 --- a/packages/surveys/src/lib/styles.test.ts +++ b/packages/surveys/src/lib/styles.test.ts @@ -26,8 +26,6 @@ const getBaseWorkspaceStyling = (overrides: Partial = {}): TW cardBackgroundColor: null, cardBorderColor: null, - questionColor: null, - inputColor: null, inputBorderColor: null, roundness: null, // defaults to 8 in addCustomThemeToDom if null here hideProgressBar: null, @@ -297,12 +295,14 @@ describe("addCustomThemeToDom", () => { test("should apply all survey styling properties", () => { const styling: TSurveyStyling = { brandColor: { light: "#112233" }, - questionColor: { light: "#AABBCC" }, + elementHeadlineColor: { light: "#AABBCC" }, + elementDescriptionColor: { light: "#AABBCC" }, + inputTextColor: { light: "#334455" }, inputBorderColor: { light: "#DDDDDD" }, cardBackgroundColor: { light: "#EEEEEE" }, cardBorderColor: { light: "#CCCCCC" }, - inputColor: { light: "#F0F0F0" }, + inputBgColor: { light: "#F0F0F0" }, roundness: 12, hideProgressBar: false, background: { bg: "#ABCDEF", bgType: "color", brightness: 100 }, @@ -350,8 +350,8 @@ describe("addCustomThemeToDom", () => { const styling: TSurveyStyling = { ...getBaseWorkspaceStyling(), // Buttons - buttonBgColor: { light: "#btn-bg" }, - buttonTextColor: { light: "#btn-text" }, + buttonBgColor: { light: "#AA1122" }, + buttonTextColor: { light: "#BB2233" }, buttonBorderRadius: 4, buttonHeight: "40", buttonFontSize: 16, @@ -359,7 +359,7 @@ describe("addCustomThemeToDom", () => { buttonPaddingX: 20, buttonPaddingY: 10, // Inputs - inputTextColor: { light: "#input-text" }, + inputTextColor: { light: "#334455" }, inputBorderRadius: 4, inputHeight: 40, inputFontSize: 14, @@ -368,9 +368,9 @@ describe("addCustomThemeToDom", () => { inputPlaceholderOpacity: 0.5, inputShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.05)", // Options - optionBgColor: { light: "#option-bg" }, - optionLabelColor: { light: "#option-label" }, - optionBorderColor: { light: "#option-border" }, + optionBgColor: { light: "#CC4455" }, + optionLabelColor: { light: "#DD5566" }, + optionBorderColor: { light: "#EE6677" }, optionBorderRadius: 4, optionPaddingX: 12, optionPaddingY: 8, @@ -378,13 +378,13 @@ describe("addCustomThemeToDom", () => { // Element Headline & Description elementHeadlineFontSize: 24, elementHeadlineFontWeight: "bold", - elementHeadlineColor: { light: "#headline-color" }, + elementHeadlineColor: { light: "#223344" }, elementDescriptionFontSize: 16, - elementDescriptionColor: { light: "#desc-color" }, + elementDescriptionColor: { light: "#445566" }, // Progress Bar progressTrackHeight: 4, - progressTrackBgColor: { light: "#track-bg" }, - progressIndicatorBgColor: { light: "#indicator-bg" }, + progressTrackBgColor: { light: "#667788" }, + progressIndicatorBgColor: { light: "#778899" }, }; addCustomThemeToDom({ styling }); @@ -392,8 +392,8 @@ describe("addCustomThemeToDom", () => { const variables = getCssVariables(styleElement); // Buttons - expect(variables["--fb-button-bg-color"]).toBe("#btn-bg"); - expect(variables["--fb-button-text-color"]).toBe("#btn-text"); + expect(variables["--fb-button-bg-color"]).toBe("#AA1122"); + expect(variables["--fb-button-text-color"]).toBe("#BB2233"); expect(variables["--fb-button-border-radius"]).toBe("4px"); expect(variables["--fb-button-height"]).toBe("40px"); expect(variables["--fb-button-font-size"]).toBe("16px"); @@ -401,7 +401,7 @@ describe("addCustomThemeToDom", () => { expect(variables["--fb-button-padding-x"]).toBe("20px"); expect(variables["--fb-button-padding-y"]).toBe("10px"); // Inputs - expect(variables["--fb-input-text-color"]).toBe("#input-text"); + expect(variables["--fb-input-text-color"]).toBe("#334455"); expect(variables["--fb-input-border-radius"]).toBe("4px"); expect(variables["--fb-input-height"]).toBe("40px"); expect(variables["--fb-input-font-size"]).toBe("14px"); @@ -410,9 +410,9 @@ describe("addCustomThemeToDom", () => { expect(variables["--fb-input-placeholder-opacity"]).toBe("0.5"); expect(variables["--fb-input-shadow"]).toBe("0 1px 2px 0 rgba(0, 0, 0, 0.05)"); // Options - expect(variables["--fb-option-bg-color"]).toBe("#option-bg"); - expect(variables["--fb-option-label-color"]).toBe("#option-label"); - expect(variables["--fb-option-border-color"]).toBe("#option-border"); + expect(variables["--fb-option-bg-color"]).toBe("#CC4455"); + expect(variables["--fb-option-label-color"]).toBe("#DD5566"); + expect(variables["--fb-option-border-color"]).toBe("#EE6677"); expect(variables["--fb-option-border-radius"]).toBe("4px"); expect(variables["--fb-option-padding-x"]).toBe("12px"); expect(variables["--fb-option-padding-y"]).toBe("8px"); @@ -420,13 +420,13 @@ describe("addCustomThemeToDom", () => { // Element Headline & Description expect(variables["--fb-element-headline-font-size"]).toBe("24px"); expect(variables["--fb-element-headline-font-weight"]).toBe("bold"); - expect(variables["--fb-element-headline-color"]).toBe("#headline-color"); + expect(variables["--fb-element-headline-color"]).toBe("#223344"); expect(variables["--fb-element-description-font-size"]).toBe("16px"); - expect(variables["--fb-element-description-color"]).toBe("#desc-color"); + expect(variables["--fb-element-description-color"]).toBe("#445566"); // Progress Bar expect(variables["--fb-progress-track-height"]).toBe("4px"); - expect(variables["--fb-progress-track-bg-color"]).toBe("#track-bg"); - expect(variables["--fb-progress-indicator-bg-color"]).toBe("#indicator-bg"); + expect(variables["--fb-progress-track-bg-color"]).toBe("#667788"); + expect(variables["--fb-progress-indicator-bg-color"]).toBe("#778899"); }); test("should format dimensions correctly", () => { @@ -449,46 +449,27 @@ describe("addCustomThemeToDom", () => { test("should derive input-placeholder-color from inputTextColor when set", () => { const styling: TSurveyStyling = { ...getBaseWorkspaceStyling(), - questionColor: { light: "#AABBCC" }, inputTextColor: { light: "#112233" }, }; addCustomThemeToDom({ styling }); const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement; const variables = getCssVariables(styleElement); - // Placeholder should be derived from inputTextColor, not questionColor - expect(variables["--fb-input-placeholder-color"]).toBeDefined(); - expect(variables["--fb-placeholder-color"]).toBeDefined(); - // Both should be based on inputTextColor (#112233) mixed with white, not questionColor (#AABBCC) - // We can verify by checking the placeholder color doesn't contain the questionColor mix - expect(variables["--fb-input-placeholder-color"]).toBe(variables["--fb-placeholder-color"]); - }); - - test("should derive input-placeholder-color from questionColor when inputTextColor is not set", () => { - const styling: TSurveyStyling = { - ...getBaseWorkspaceStyling(), - questionColor: { light: "#AABBCC" }, - }; - addCustomThemeToDom({ styling }); - const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement; - const variables = getCssVariables(styleElement); - - // Placeholder should fall back to questionColor when inputTextColor is not set expect(variables["--fb-input-placeholder-color"]).toBeDefined(); expect(variables["--fb-placeholder-color"]).toBeDefined(); expect(variables["--fb-input-placeholder-color"]).toBe(variables["--fb-placeholder-color"]); }); - test("should set signature and branding text colors for dark questionColor", () => { + test("should set signature and branding text colors for dark elementHeadlineColor", () => { const styling = getBaseWorkspaceStyling({ - questionColor: { light: "#202020" }, // A dark color - brandColor: { light: "#123456" }, // brandColor needed for some default fallbacks if not directly testing them + elementHeadlineColor: { light: "#202020" }, // A dark color + brandColor: { light: "#123456" }, }); addCustomThemeToDom({ styling }); const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement; const variables = getCssVariables(styleElement); - // For dark questionColor ('#202020'), isLight is false, so mix with white. + // For dark elementHeadlineColor ('#202020'), isLight is false, so mix with white. expect(variables["--fb-signature-text-color"]).toBeDefined(); expect(variables["--fb-branding-text-color"]).toBeDefined(); }); @@ -501,11 +482,11 @@ describe("addCustomThemeToDom", () => { expect(variables["--fb-border-radius"]).toBe("0px"); }); - test("should set input-background-color-selected to slate-50 for white inputColor", () => { + test("should set input-background-color-selected to slate-50 for white inputBgColor", () => { const whiteColors = ["#fff", "#ffffff", "white"]; whiteColors.forEach((color) => { const styling = getBaseWorkspaceStyling({ - inputColor: { light: color }, + inputBgColor: { light: color }, brandColor: { light: "#123" }, }); addCustomThemeToDom({ styling }); @@ -515,9 +496,9 @@ describe("addCustomThemeToDom", () => { }); }); - test("should mix input-background-color-selected for non-white inputColor", () => { + test("should mix input-background-color-selected for non-white inputBgColor", () => { const styling = getBaseWorkspaceStyling({ - inputColor: { light: "#E0E0E0" }, + inputBgColor: { light: "#E0E0E0" }, brandColor: { light: "#123" }, }); // Not white addCustomThemeToDom({ styling }); @@ -618,9 +599,6 @@ describe("getBaseWorkspaceStyling_Helper", () => { expect(baseStyling.cardBackgroundColor).toBeNull(); expect(baseStyling.cardBorderColor).toBeNull(); - expect(baseStyling.questionColor).toBeNull(); - // Specifically testing lines highlighted by user - expect(baseStyling.inputColor).toBeNull(); expect(baseStyling.inputBorderColor).toBeNull(); expect(baseStyling.roundness).toBeNull(); expect(baseStyling.hideProgressBar).toBeNull(); @@ -632,7 +610,7 @@ describe("getBaseWorkspaceStyling_Helper", () => { test("should correctly apply overrides to specified properties", () => { const overrides: Partial = { - inputColor: { light: "#111" }, + inputBgColor: { light: "#111" }, inputBorderColor: { light: "#222" }, roundness: 10, hideProgressBar: true, @@ -642,7 +620,7 @@ describe("getBaseWorkspaceStyling_Helper", () => { }; const styled = getBaseWorkspaceStyling(overrides); - expect(styled.inputColor).toEqual({ light: "#111" }); + expect(styled.inputBgColor).toEqual({ light: "#111" }); expect(styled.inputBorderColor).toEqual({ light: "#222" }); expect(styled.roundness).toBe(10); expect(styled.hideProgressBar).toBe(true); diff --git a/packages/surveys/src/lib/styles.ts b/packages/surveys/src/lib/styles.ts index 0f5509ee66..00b18f5fb0 100644 --- a/packages/surveys/src/lib/styles.ts +++ b/packages/surveys/src/lib/styles.ts @@ -102,16 +102,14 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | appendCssVariable("brand-text-color", "#ffffff"); } - // Backwards-compat: legacy variables still used by some consumers/tests - appendCssVariable("heading-color", styling.questionColor?.light); - appendCssVariable("element-headline-color", styling.questionColor?.light); - appendCssVariable("element-description-color", styling.questionColor?.light); - appendCssVariable("input-color", styling.questionColor?.light); - appendCssVariable("label-color", styling.questionColor?.light); - // Backwards-compat: legacy variables still used by some consumers/tests - appendCssVariable("subheading-color", styling.questionColor?.light); + appendCssVariable("heading-color", styling.elementHeadlineColor?.light); + appendCssVariable("element-headline-color", styling.elementHeadlineColor?.light); + appendCssVariable("element-description-color", styling.elementDescriptionColor?.light); + appendCssVariable("input-color", styling.inputTextColor?.light); + appendCssVariable("label-color", styling.elementUpperLabelColor?.light); + appendCssVariable("subheading-color", styling.elementDescriptionColor?.light); - const placeholderBaseColor = styling.inputTextColor?.light ?? styling.questionColor?.light; + const placeholderBaseColor = styling.inputTextColor?.light; if (placeholderBaseColor) { appendCssVariable("placeholder-color", mixColor(placeholderBaseColor, "#ffffff", 0.3)); appendCssVariable("input-placeholder-color", mixColor(placeholderBaseColor, "#ffffff", 0.3)); @@ -142,21 +140,21 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | appendCssVariable("input-border-radius", formatDimension(roundness)); appendCssVariable("option-border-radius", formatDimension(roundness)); appendCssVariable("button-border-radius", formatDimension(roundness)); - appendCssVariable("input-background-color", styling.inputColor?.light); - appendCssVariable("input-bg-color", styling.inputColor?.light); - appendCssVariable("option-bg-color", styling.inputColor?.light); - appendCssVariable("input-color", styling.questionColor?.light); + appendCssVariable("input-background-color", styling.inputBgColor?.light); + appendCssVariable("input-bg-color", styling.inputBgColor?.light); + appendCssVariable("option-bg-color", styling.optionBgColor?.light); + appendCssVariable("input-color", styling.inputTextColor?.light); - if (styling.questionColor?.light) { - const isLightQuestionColor = isLight(styling.questionColor.light); + if (styling.elementHeadlineColor?.light) { + const isLightHeadlineColor = isLight(styling.elementHeadlineColor.light); const signatureColor = mixColor( - styling.questionColor.light, - isLightQuestionColor ? "#000000" : "#ffffff", + styling.elementHeadlineColor.light, + isLightHeadlineColor ? "#000000" : "#ffffff", 0.2 ); const brandingColor = mixColor( - styling.questionColor.light, - isLightQuestionColor ? "#000000" : "#ffffff", + styling.elementHeadlineColor.light, + isLightHeadlineColor ? "#000000" : "#ffffff", 0.3 ); @@ -164,17 +162,17 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | appendCssVariable("branding-text-color", brandingColor); } - if (styling.inputColor?.light) { + if (styling.inputBgColor?.light) { if ( - styling.inputColor.light === "#fff" || - styling.inputColor.light === "#ffffff" || - styling.inputColor.light === "white" + styling.inputBgColor.light === "#fff" || + styling.inputBgColor.light === "#ffffff" || + styling.inputBgColor.light === "white" ) { appendCssVariable("input-background-color-selected", "var(--slate-50)"); } else { appendCssVariable( "input-background-color-selected", - mixColor(styling.inputColor.light, "#000000", 0.025) + mixColor(styling.inputBgColor.light, "#000000", 0.025) ); } } @@ -194,7 +192,7 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | } // Buttons (Advanced) - const buttonBg = styling.buttonBgColor?.light ?? styling.brandColor?.light; + const buttonBg = styling.buttonBgColor?.light; let buttonText = styling.buttonTextColor?.light; if (buttonText === undefined && buttonBg) { buttonText = isLight(buttonBg) ? "#0f172a" : "#ffffff"; @@ -215,8 +213,8 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | appendCssVariable("button-padding-y", formatDimension(styling.buttonPaddingY)); // Inputs (Advanced) - appendCssVariable("input-background-color", styling.inputBgColor?.light ?? styling.inputColor?.light); - const inputTextColor = styling.inputTextColor?.light ?? styling.questionColor?.light; + appendCssVariable("input-background-color", styling.inputBgColor?.light); + const inputTextColor = styling.inputTextColor?.light; appendCssVariable("input-text-color", inputTextColor); if (inputTextColor) { appendCssVariable("input-placeholder-color", mixColor(inputTextColor, "#ffffff", 0.3)); @@ -236,8 +234,8 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | appendCssVariable("input-shadow", styling.inputShadow); // Options (Advanced) - appendCssVariable("option-bg-color", styling.optionBgColor?.light ?? styling.inputColor?.light); - appendCssVariable("option-label-color", styling.optionLabelColor?.light ?? styling.questionColor?.light); + appendCssVariable("option-bg-color", styling.optionBgColor?.light); + appendCssVariable("option-label-color", styling.optionLabelColor?.light); if (styling.optionBorderColor?.light) appendCssVariable("option-border-color", styling.optionBorderColor.light); if (styling.optionBorderRadius !== undefined) @@ -254,28 +252,19 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | appendCssVariable("element-headline-font-size", formatDimension(styling.elementHeadlineFontSize)); if (styling.elementHeadlineFontWeight !== undefined && styling.elementHeadlineFontWeight !== null) appendCssVariable("element-headline-font-weight", `${styling.elementHeadlineFontWeight}`); - appendCssVariable( - "element-headline-color", - styling.elementHeadlineColor?.light ?? styling.questionColor?.light - ); + appendCssVariable("element-headline-color", styling.elementHeadlineColor?.light); if (styling.elementDescriptionFontSize !== undefined) appendCssVariable("element-description-font-size", formatDimension(styling.elementDescriptionFontSize)); if (styling.elementDescriptionFontWeight !== undefined && styling.elementDescriptionFontWeight !== null) appendCssVariable("element-description-font-weight", `${styling.elementDescriptionFontWeight}`); - appendCssVariable( - "element-description-color", - styling.elementDescriptionColor?.light ?? styling.questionColor?.light - ); + appendCssVariable("element-description-color", styling.elementDescriptionColor?.light); appendCssVariable( "element-upper-label-font-size", formatDimension(styling.elementUpperLabelFontSize ?? 12) ); - appendCssVariable( - "element-upper-label-color", - styling.elementUpperLabelColor?.light ?? styling.questionColor?.light - ); + appendCssVariable("element-upper-label-color", styling.elementUpperLabelColor?.light); if (styling.elementUpperLabelColor?.light) { appendCssVariable("element-upper-label-opacity", "1"); @@ -290,15 +279,8 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | // Implicitly set the progress track border radius to the roundness of the card appendCssVariable("progress-track-border-radius", formatDimension(roundness)); - appendCssVariable( - "progress-track-bg-color", - styling.progressTrackBgColor?.light ?? - (styling.brandColor?.light ? mixColor(styling.brandColor.light, "#ffffff", 0.8) : undefined) - ); - appendCssVariable( - "progress-indicator-bg-color", - styling.progressIndicatorBgColor?.light ?? styling.brandColor?.light - ); + appendCssVariable("progress-track-bg-color", styling.progressTrackBgColor?.light); + appendCssVariable("progress-indicator-bg-color", styling.progressIndicatorBgColor?.light); // Close the #fbjs variable block cssVariables += "}\n"; @@ -324,7 +306,7 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | headlineDecls += " font-size: var(--fb-element-headline-font-size) !important;\n"; if (styling.elementHeadlineFontWeight !== undefined && styling.elementHeadlineFontWeight !== null) headlineDecls += " font-weight: var(--fb-element-headline-font-weight) !important;\n"; - if (styling.elementHeadlineColor?.light || styling.questionColor?.light) + if (styling.elementHeadlineColor?.light) headlineDecls += " color: var(--fb-element-headline-color) !important;\n"; addRule("#fbjs .label-headline,\n#fbjs .label-headline *", headlineDecls); @@ -334,7 +316,7 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | descriptionDecls += " font-size: var(--fb-element-description-font-size) !important;\n"; if (styling.elementDescriptionFontWeight !== undefined && styling.elementDescriptionFontWeight !== null) descriptionDecls += " font-weight: var(--fb-element-description-font-weight) !important;\n"; - if (styling.elementDescriptionColor?.light || styling.questionColor?.light) + if (styling.elementDescriptionColor?.light) descriptionDecls += " color: var(--fb-element-description-color) !important;\n"; addRule("#fbjs .label-description,\n#fbjs .label-description *", descriptionDecls); @@ -344,7 +326,7 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | upperDecls += " font-size: var(--fb-element-upper-label-font-size) !important;\n"; if (styling.elementUpperLabelFontWeight !== undefined && styling.elementUpperLabelFontWeight !== null) upperDecls += " font-weight: var(--fb-element-upper-label-font-weight) !important;\n"; - if (styling.elementUpperLabelColor?.light || styling.questionColor?.light) { + if (styling.elementUpperLabelColor?.light) { upperDecls += " color: var(--fb-element-upper-label-color) !important;\n"; upperDecls += " opacity: var(--fb-element-upper-label-opacity, 1) !important;\n"; } @@ -352,10 +334,8 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | // --- Buttons --- let buttonDecls = ""; - if (styling.buttonBgColor?.light || styling.brandColor?.light) - buttonDecls += " background-color: var(--fb-button-bg-color) !important;\n"; - if (styling.buttonTextColor?.light || styling.brandColor?.light) - buttonDecls += " color: var(--fb-button-text-color) !important;\n"; + if (buttonBg) buttonDecls += " background-color: var(--fb-button-bg-color) !important;\n"; + if (buttonText) buttonDecls += " color: var(--fb-button-text-color) !important;\n"; if (styling.buttonBorderRadius !== undefined) buttonDecls += " border-radius: var(--fb-button-border-radius) !important;\n"; if (styling.buttonHeight !== undefined) buttonDecls += " height: var(--fb-button-height) !important;\n"; @@ -378,11 +358,11 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | addRule("#fbjs .rounded-option", " border-radius: var(--fb-option-border-radius) !important;\n"); if (styling.optionBorderColor?.light) addRule("#fbjs .border-option-border", " border-color: var(--fb-option-border-color) !important;\n"); - if (styling.optionBgColor?.light || styling.inputColor?.light) + if (styling.optionBgColor?.light) addRule("#fbjs .bg-option-bg", " background-color: var(--fb-option-bg-color) !important;\n"); let optionLabelDecls = ""; - if (styling.optionLabelColor?.light || styling.questionColor?.light) + if (styling.optionLabelColor?.light) optionLabelDecls += " color: var(--fb-option-label-color) !important;\n"; if (styling.optionFontSize !== undefined) optionLabelDecls += " font-size: var(--fb-option-font-size) !important;\n"; @@ -402,14 +382,13 @@ export const addCustomThemeToDom = ({ styling }: { styling: TWorkspaceStyling | // --- Inputs --- if (styling.inputBorderRadius !== undefined) addRule("#fbjs .rounded-input", " border-radius: var(--fb-input-border-radius) !important;\n"); - if (styling.inputBgColor?.light || styling.inputColor?.light) + if (styling.inputBgColor?.light) addRule("#fbjs .bg-input-bg", " background-color: var(--fb-input-background-color) !important;\n"); if (styling.inputBorderColor?.light) addRule("#fbjs .border-input-border", " border-color: var(--fb-input-border-color) !important;\n"); let inputTextDecls = ""; - if (styling.inputTextColor?.light || styling.questionColor?.light) - inputTextDecls += " color: var(--fb-input-text-color) !important;\n"; + if (styling.inputTextColor?.light) inputTextDecls += " color: var(--fb-input-text-color) !important;\n"; if (styling.inputFontSize !== undefined) inputTextDecls += " font-size: var(--fb-input-font-size) !important;\n"; addRule("#fbjs .text-input-text", inputTextDecls); diff --git a/packages/types/styling.ts b/packages/types/styling.ts index f475f8d346..e417261164 100644 --- a/packages/types/styling.ts +++ b/packages/types/styling.ts @@ -95,9 +95,6 @@ export const ZBaseStyling = z.object({ progressTrackBgColor: ZStylingColor.nullish(), progressIndicatorBgColor: ZStylingColor.nullish(), - questionColor: ZStylingColor.nullish(), - inputColor: ZStylingColor.nullish(), // legacy? keep for compat? - // inputBorderColor: ZStylingColor.nullish(), // defined above cardBackgroundColor: ZStylingColor.nullish(), cardBorderColor: ZStylingColor.nullish(), highlightBorderColor: ZStylingColor.nullish(),