Compare commits

...

2 Commits

Author SHA1 Message Date
Dhruwang
e94f82ea99 removed duplicate name 2025-11-25 11:27:25 +05:30
Dhruwang
f599062def refactor(surveys): remove fb- prefix from Tailwind classes
- Remove 'fb-' prefix from Tailwind config in surveys package
- Update all TSX components to use standard Tailwind classes
- Update CSS files to remove fb- prefix from class names
- Update CSS variable references from --fb-* to --*
- Update test files to expect new variable names
- Update Storybook Tailwind config to include survey package content

This change simplifies development by using standard Tailwind classes
instead of prefixed ones, while maintaining style isolation through
the #fbjs container and important selector.
2025-11-25 10:42:34 +05:30
47 changed files with 449 additions and 484 deletions

View File

@@ -3,5 +3,10 @@ import base from "../web/tailwind.config";
export default {
...base,
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}", "../web/modules/ui/**/*.{js,ts,jsx,tsx}"],
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
"../web/modules/ui/**/*.{js,ts,jsx,tsx}",
"../../packages/surveys/src/**/*.{js,ts,jsx,tsx}",
],
};

View File

@@ -15,7 +15,7 @@ export function BackButton({ onClick, backButtonLabel, tabIndex = 2 }: BackButto
tabIndex={tabIndex}
type="button"
className={cn(
"fb-mb-1 hover:fb-bg-input-bg fb-text-heading focus:fb-ring-focus fb-rounded-custom fb-flex fb-items-center fb-px-3 fb-py-3 fb-text-base fb-font-medium fb-leading-4 focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-offset-2"
"hover:bg-input-bg text-heading focus:ring-focus rounded-custom mb-1 flex items-center px-3 py-3 text-base font-medium leading-4 focus:outline-none focus:ring-2 focus:ring-offset-2"
)}
onClick={onClick}>
{backButtonLabel || t("common.back")}

View File

@@ -72,7 +72,7 @@ export function SubmitButton({
type={type}
tabIndex={tabIndex}
autoFocus={focus}
className="fb-bg-brand fb-border-submit-button-border fb-text-on-brand focus:fb-ring-focus fb-rounded-custom fb-flex fb-items-center fb-border fb-px-3 fb-py-3 fb-text-base fb-font-medium fb-leading-4 fb-shadow-sm hover:fb-opacity-90 focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-offset-2 fb-mb-1"
className="bg-brand border-submit-button-border text-on-brand focus:ring-focus rounded-custom mb-1 flex items-center border px-3 py-3 text-base font-medium leading-4 shadow-sm hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-offset-2"
onClick={onClick}
disabled={disabled}>
{buttonLabel || (isLastQuestion ? t("common.finish") : t("common.next"))}

View File

@@ -4,10 +4,10 @@ interface AutoCloseProgressBarProps {
export function AutoCloseProgressBar({ autoCloseTimeout }: AutoCloseProgressBarProps) {
return (
<div className="fb-bg-accent-bg fb-h-2 fb-w-full fb-overflow-hidden">
<div className="bg-accent-bg h-2 w-full overflow-hidden">
<div
key={autoCloseTimeout}
className="fb-bg-brand fb-z-20 fb-h-2"
className="bg-brand z-20 h-2"
style={{
animation: `shrink-width-to-zero ${autoCloseTimeout.toString()}s linear forwards`,
width: "100%",

View File

@@ -48,14 +48,14 @@ export function CalEmbed({ question, onSuccessfulBooking }: CalEmbedProps) {
});
cal("init", { calOrigin: question.calHost ? `https://${question.calHost}` : "https://cal.com" });
cal("inline", {
elementOrSelector: "#fb-cal-embed",
elementOrSelector: "#cal-embed",
calLink: question.calUserName,
});
}, [cal, question.calHost, question.calUserName]);
return (
<div className="fb-relative fb-mt-4 fb-overflow-auto">
<div id="fb-cal-embed" className={cn("fb-border-border fb-rounded-lg fb-border")} />
<div className="relative mt-4 overflow-auto">
<div id="cal-embed" className={cn("border-border rounded-lg border")} />
</div>
);
}

View File

@@ -48,21 +48,21 @@ export function EndingCard({
) : null;
const checkmark = (
<div className="fb-text-brand fb-flex fb-flex-col fb-items-center fb-justify-center">
<div className="text-brand flex flex-col items-center justify-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="1.5"
stroke="currentColor"
className="fb-h-24 fb-w-24">
className="h-24 w-24">
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span className="fb-bg-brand fb-mb-[10px] fb-inline-block fb-h-1 fb-w-16 fb-rounded-[100%]" />
<span className="bg-brand mb-[10px] inline-block h-1 w-16 rounded-[100%]" />
</div>
);
@@ -115,7 +115,7 @@ export function EndingCard({
return (
<ScrollableContainer fullSizeCards={fullSizeCards}>
<div className="fb-text-center">
<div className="text-center">
{isResponseSendingFinished ? (
<>
{endingCard.type === "endScreen" && (
@@ -140,7 +140,7 @@ export function EndingCard({
questionId="EndingCard"
/>
{endingCard.buttonLabel ? (
<div className="fb-mt-6 fb-flex fb-w-full fb-flex-col fb-items-center fb-justify-center fb-space-y-4">
<div className="mt-6 flex w-full flex-col items-center justify-center space-y-4">
<SubmitButton
buttonLabel={replaceRecallInfo(
getLocalizedValue(endingCard.buttonLabel, languageCode),
@@ -171,7 +171,7 @@ export function EndingCard({
/>
</div>
) : (
<div className="fb-my-3">
<div className="my-3">
<LoadingSpinner />
</div>
)}
@@ -180,10 +180,10 @@ export function EndingCard({
</>
) : (
<>
<div className="fb-my-3">
<div className="my-3">
<LoadingSpinner />
</div>
<h1 className="fb-text-brand">{t("common.sending_responses")}</h1>
<h1 className="text-brand">{t("common.sending_responses")}</h1>
</>
)}
</div>

View File

@@ -21,14 +21,9 @@ export function ErrorComponent({ errorType }: ErrorComponentProps) {
const error = errorData[errorType];
return (
<div
className="fb-flex fb-flex-col fb-bg-white fb-p-8 fb-text-center fb-items-center"
role="alert"
aria-live="assertive">
<span className="fb-mb-1.5 fb-text-base fb-font-bold fb-leading-6 fb-text-slate-900">
{error.title}
</span>
<p className="fb-max-w-lg fb-text-sm fb-font-normal fb-leading-6 fb-text-slate-600">{error.message}</p>
<div className="flex flex-col items-center bg-white p-8 text-center" role="alert" aria-live="assertive">
<span className="mb-1.5 text-base font-bold leading-6 text-slate-900">{error.title}</span>
<p className="max-w-lg text-sm font-normal leading-6 text-slate-600">{error.message}</p>
</div>
);
}

View File

@@ -327,7 +327,7 @@ export function FileInput({
}, [allowedFileExtensions]);
return (
<div className="fb-bg-input-bg hover:fb-bg-input-bg-selected fb-border-border fb-relative fb-mt-3 fb-flex fb-w-full fb-flex-col fb-justify-center fb-items-center fb-rounded-lg fb-border-2 fb-border-dashed dark:fb-border-slate-600 dark:fb-bg-slate-700 dark:hover:fb-border-slate-500 dark:hover:fb-bg-slate-800">
<div className="bg-input-bg hover:bg-input-bg-selected border-border relative mt-3 flex w-full flex-col items-center justify-center rounded-lg border-2 border-dashed dark:border-slate-600 dark:bg-slate-700 dark:hover:border-slate-500 dark:hover:bg-slate-800">
<div ref={parent}>
{fileUrls?.map((fileUrl, index) => {
const fileName = getOriginalFileNameFromUrl(fileUrl);
@@ -336,19 +336,19 @@ export function FileInput({
key={index}
aria-label={t("common.you_have_successfully_uploaded_the_file", { fileName })}
tabIndex={0}
className="fb-bg-input-bg-selected fb-border-border fb-relative fb-m-2 fb-rounded-md fb-border">
<div className="fb-absolute fb-right-0 fb-top-0 fb-m-2">
className="bg-input-bg-selected border-border relative m-2 rounded-md border">
<div className="absolute right-0 top-0 m-2">
<button
type="button"
aria-label={`${t("common.delete_file")} ${fileName}`}
className="fb-bg-survey-bg fb-flex fb-h-5 fb-w-5 fb-cursor-pointer fb-items-center fb-justify-center fb-rounded-md">
className="bg-survey-bg flex h-5 w-5 cursor-pointer items-center justify-center rounded-md">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 26 26"
strokeWidth={1}
stroke="currentColor"
className="fb-text-heading fb-h-5"
className="text-heading h-5"
onClick={(e) => {
handleDeleteFile(index, e);
}}>
@@ -356,7 +356,7 @@ export function FileInput({
</svg>
</button>
</div>
<div className="fb-flex fb-flex-col fb-items-center fb-justify-center fb-p-2">
<div className="flex flex-col items-center justify-center p-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
@@ -367,12 +367,12 @@ export function FileInput({
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="fb-text-heading fb-h-6"
className="text-heading h-6"
aria-hidden="true">
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" />
<polyline points="14 2 14 8 20 8" />
</svg>
<p className="fb-text-heading fb-mt-1 fb-w-full fb-overflow-hidden fb-overflow-ellipsis fb-whitespace-nowrap fb-px-2 fb-text-center fb-text-sm">
<p className="text-heading mt-1 w-full overflow-hidden overflow-ellipsis whitespace-nowrap px-2 text-center text-sm">
{fileName}
</p>
</div>
@@ -383,8 +383,8 @@ export function FileInput({
<div>
{isUploading ? (
<div className="fb-inset-0 fb-flex fb-animate-pulse fb-items-center fb-justify-center fb-rounded-lg fb-py-4">
<label htmlFor={uniqueHtmlFor} className="fb-text-subheading fb-text-sm fb-font-medium">
<div className="inset-0 flex animate-pulse items-center justify-center rounded-lg py-4">
<label htmlFor={uniqueHtmlFor} className="text-subheading text-sm font-medium">
{t("common.uploading")}...
</label>
</div>
@@ -394,7 +394,7 @@ export function FileInput({
{showUploader ? (
<button
type="button"
className="focus:fb-outline-brand fb-flex fb-flex-col fb-items-center fb-justify-center fb-py-6 hover:fb-cursor-pointer w-full"
className="focus:outline-brand flex w-full flex-col items-center justify-center py-6 hover:cursor-pointer"
aria-label={t("common.upload_files_by_clicking_or_dragging_them_here")}
onClick={() => document.getElementById(uniqueHtmlFor)?.click()}>
<svg
@@ -403,7 +403,7 @@ export function FileInput({
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="fb-text-placeholder fb-h-6"
className="text-placeholder h-6"
aria-hidden="true">
<path
strokeLinecap="round"
@@ -412,7 +412,7 @@ export function FileInput({
/>
</svg>
<span
className="fb-text-placeholder fb-mt-2 fb-text-sm dark:fb-text-slate-400"
className="text-placeholder mt-2 text-sm dark:text-slate-400"
id={`${uniqueHtmlFor}-label`}>
{t("common.click_or_drag_to_upload_files")}
</span>
@@ -421,7 +421,7 @@ export function FileInput({
id={uniqueHtmlFor}
name={uniqueHtmlFor}
accept={mimeTypeForAllowedFileExtensions}
className="fb-hidden"
className="hidden"
onChange={async (e) => {
const inputElement = e.target as HTMLInputElement;
if (inputElement.files) {

View File

@@ -3,16 +3,16 @@ import { useTranslation } from "react-i18next";
export function FormbricksBranding() {
const { t } = useTranslation();
return (
<span className="fb-flex fb-justify-center">
<span className="flex justify-center">
<a
href="https://formbricks.com?utm_source=survey_branding"
target="_blank"
tabIndex={-1}
rel="noopener">
<p className="fb-text-signature fb-text-xs">
<p className="text-signature text-xs">
{t("common.powered_by")}{" "}
<b>
<span className="fb-text-branding-text hover:fb-text-signature">Formbricks</span>
<span className="text-branding-text hover:text-signature">Formbricks</span>
</b>
</p>
</a>

View File

@@ -24,26 +24,26 @@ export function Headline({ headline, questionId, required = true, alignTextCente
: "";
return (
<label htmlFor={questionId} className="fb-text-heading fb-mb-[3px] fb-flex fb-flex-col">
<label htmlFor={questionId} className="text-heading mb-[3px] flex flex-col">
{!required && (
<span
className="fb-text-xs fb-opacity-60 fb-font-normal fb-leading-6 fb-mb-[3px]"
className="mb-[3px] text-xs font-normal leading-6 opacity-60"
tabIndex={-1}
data-testid="fb__surveys__headline-optional-text-test">
{t("common.optional")}
</span>
)}
<div
className={`fb-flex fb-items-center ${alignTextCenter ? "fb-justify-center" : "fb-justify-between"}`}
className={`flex items-center ${alignTextCenter ? "justify-center" : "justify-between"}`}
dir="auto">
{isHeadlineHtml ? (
<div
data-testid="fb__surveys__headline-text-test"
className="fb-htmlbody fb-text-base"
className="htmlbody text-base"
dangerouslySetInnerHTML={{ __html: safeHtml }}
/>
) : (
<p data-testid="fb__surveys__headline-text-test" className="fb-text-base fb-font-semibold">
<p data-testid="fb__surveys__headline-text-test" className="text-base font-semibold">
{headline}
</p>
)}

View File

@@ -9,7 +9,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(({ className, ...p
<input
ref={ref} // Forward the ref to the input element
className={cn(
"focus:fb-border-brand fb-bg-input-bg fb-flex fb-w-full fb-border fb-border-border fb-rounded-custom fb-px-3 fb-py-2 fb-text-sm fb-text-subheading placeholder:fb-text-placeholder focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-offset-2 disabled:fb-cursor-not-allowed disabled:fb-opacity-50 dark:fb-border-slate-500 dark:fb-text-slate-300",
"focus:border-brand bg-input-bg border-border rounded-custom text-subheading placeholder:text-placeholder flex w-full border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-500 dark:text-slate-300",
className ?? ""
)}
dir="auto"

View File

@@ -5,7 +5,7 @@ interface LabelProps {
export function Label({ text, htmlForId }: Readonly<LabelProps>) {
return (
<label htmlFor={htmlForId} className="fb-text-subheading fb-font-normal fb-text-sm fb-block" dir="auto">
<label htmlFor={htmlForId} className="text-subheading block text-sm font-normal" dir="auto">
{text}
</label>
);

View File

@@ -75,12 +75,12 @@ export function LanguageSwitch({
});
return (
<div className="fb-z-[1001] fb-flex fb-w-fit fb-items-center">
<div className="z-[1001] flex w-fit items-center">
<button
title={t("common.language_switch")}
type="button"
className={cn(
"fb-text-heading fb-relative fb-h-8 fb-w-8 fb-rounded-md focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-offset-2 fb-justify-center fb-flex fb-items-center"
"text-heading relative flex h-8 w-8 items-center justify-center rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2"
)}
style={{
backgroundColor: isHovered ? hoverColorWithOpacity : "transparent",
@@ -99,8 +99,8 @@ export function LanguageSwitch({
{showLanguageDropdown ? (
<div
className={cn(
"fb-bg-brand fb-text-on-brand fb-absolute fb-top-10 fb-space-y-2 fb-rounded-md fb-p-2 fb-text-xs",
dir === "rtl" ? "fb-left-8" : "fb-right-8"
"bg-brand text-on-brand absolute top-10 space-y-2 rounded-md p-2 text-xs",
dir === "rtl" ? "left-8" : "right-8"
)}
ref={languageDropdownRef}>
{surveyLanguages.map((surveyLanguage) => {
@@ -109,7 +109,7 @@ export function LanguageSwitch({
<button
key={surveyLanguage.language.id}
type="button"
className="fb-block fb-w-full fb-p-1.5 fb-text-left hover:fb-opacity-80"
className="block w-full p-1.5 text-left hover:opacity-80"
onClick={() => {
changeLanguage(surveyLanguage.language.code);
}}>

View File

@@ -4,15 +4,15 @@ export function LoadingSpinner({ className }: { className?: string }) {
return (
<div
data-testid="loading-spinner"
className={cn("fb-flex fb-h-full fb-w-full fb-items-center fb-justify-center", className ?? "")}>
className={cn("flex h-full w-full items-center justify-center", className ?? "")}>
<svg
className="fb-m-2 fb-h-6 fb-w-6 fb-animate-spin fb-text-brand"
className="text-brand m-2 h-6 w-6 animate-spin"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24">
<circle className="fb-opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path
className="fb-opacity-75"
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>

View File

@@ -1,8 +1,8 @@
export function Progress({ progress }: { progress: number }) {
return (
<div className="fb-bg-accent-bg fb-h-2 fb-w-full fb-rounded-none">
<div className="bg-accent-bg h-2 w-full rounded-none">
<div
className="fb-transition-width fb-bg-brand fb-z-20 fb-h-2 fb-duration-500"
className="transition-width bg-brand z-20 h-2 duration-500"
style={{ width: `${Math.floor(progress * 100).toString()}%` }}
/>
</div>

View File

@@ -31,19 +31,16 @@ export function QuestionMedia({ imgUrl, videoUrl, altText = "Image" }: QuestionM
const [isLoading, setIsLoading] = useState(true);
return (
<div className="fb-group/image fb-relative fb-mb-6 fb-block fb-min-h-40 fb-rounded-md">
<div className="group/image relative mb-6 block min-h-40 rounded-md">
{isLoading ? (
<div className="fb-absolute fb-inset-auto fb-flex fb-h-full fb-w-full fb-animate-pulse fb-items-center fb-justify-center fb-rounded-md fb-bg-slate-200" />
<div className="absolute inset-auto flex h-full w-full animate-pulse items-center justify-center rounded-md bg-slate-200" />
) : null}
{imgUrl ? (
<img
key={imgUrl}
src={imgUrl}
alt={altText}
className={cn(
"fb-rounded-custom fb-max-h-[40dvh] fb-mx-auto fb-object-contain",
isLoading ? "fb-opacity-0" : ""
)}
className={cn("rounded-custom mx-auto max-h-[40dvh] object-contain", isLoading ? "opacity-0" : "")}
onLoad={() => {
setIsLoading(false);
}}
@@ -53,13 +50,13 @@ export function QuestionMedia({ imgUrl, videoUrl, altText = "Image" }: QuestionM
/>
) : null}
{videoUrlWithParams ? (
<div className="fb-relative">
<div className="fb-rounded-custom fb-bg-black">
<div className="relative">
<div className="rounded-custom bg-black">
<iframe
src={videoUrlWithParams}
title={t("common.question_video")}
frameBorder="0"
className={cn("fb-rounded-custom fb-aspect-video fb-w-full", isLoading ? "fb-opacity-0" : "")}
className={cn("rounded-custom aspect-video w-full", isLoading ? "opacity-0" : "")}
onLoad={() => {
setIsLoading(false);
}}
@@ -77,7 +74,7 @@ export function QuestionMedia({ imgUrl, videoUrl, altText = "Image" }: QuestionM
target="_blank"
rel="noreferrer"
aria-label={t("common.open_in_new_tab")}
className="fb-absolute fb-bottom-2 fb-right-2 fb-flex fb-items-center fb-gap-2 fb-rounded-md fb-bg-slate-800 fb-bg-opacity-40 fb-p-1.5 fb-text-white fb-opacity-0 fb-backdrop-blur-lg fb-transition fb-duration-300 fb-ease-in-out hover:fb-bg-opacity-65 group-hover/image:fb-opacity-100">
className="absolute bottom-2 right-2 flex items-center gap-2 rounded-md bg-slate-800 bg-opacity-40 p-1.5 text-white opacity-0 backdrop-blur-lg transition duration-300 ease-in-out hover:bg-opacity-65 group-hover/image:opacity-100">
{imgUrl ? <ImageDownIcon size={20} /> : <ExpandIcon size={20} />}
</a>
</div>

View File

@@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
export function RecaptchaBranding() {
const { t } = useTranslation();
return (
<p className="fb-text-signature fb-text-xs fb-text-center fb-leading-6 fb-text-balance">
<p className="text-signature text-balance text-center text-xs leading-6">
{t("common.protected_by_reCAPTCHA_and_the_Google")}{" "}
<b>
<a target="_blank" rel="noopener" href="https://policies.google.com/privacy">

View File

@@ -13,24 +13,24 @@ interface ResponseErrorComponentProps {
export function ResponseErrorComponent({ questions, responseData, onRetry }: ResponseErrorComponentProps) {
const { t } = useTranslation();
return (
<div className="fb-flex fb-flex-col fb-bg-white fb-p-4">
<span className="fb-mb-1.5 fb-text-base fb-font-bold fb-leading-6 fb-text-slate-900">
<div className="flex flex-col bg-white p-4">
<span className="mb-1.5 text-base font-bold leading-6 text-slate-900">
{t("common.your_feedback_is_stuck")}
</span>
<p className="fb-max-w-md fb-text-sm fb-font-normal fb-leading-6 fb-text-slate-600">
<p className="max-w-md text-sm font-normal leading-6 text-slate-600">
{t("common.the_servers_cannot_be_reached_at_the_moment")}
<br />
{t("common.please_retry_now_or_try_again_later")}
</p>
<div className="fb-mt-4 fb-rounded-lg fb-border fb-border-slate-200 fb-bg-slate-100 fb-px-4 fb-py-5">
<div className="fb-flex fb-max-h-36 fb-flex-1 fb-flex-col fb-space-y-3 fb-overflow-y-scroll">
<div className="mt-4 rounded-lg border border-slate-200 bg-slate-100 px-4 py-5">
<div className="flex max-h-36 flex-1 flex-col space-y-3 overflow-y-scroll">
{questions.map((question, index) => {
const response = responseData[question.id];
if (!response) return;
return (
<div className="fb-flex fb-flex-col" key={`response-${index.toString()}`}>
<span className="fb-text-sm fb-leading-6 fb-text-slate-900">{`${t("common.question")} ${(index + 1).toString()}`}</span>
<span className="fb-mt-1 fb-text-sm fb-font-semibold fb-leading-6 fb-text-slate-900">
<div className="flex flex-col" key={`response-${index.toString()}`}>
<span className="text-sm leading-6 text-slate-900">{`${t("common.question")} ${(index + 1).toString()}`}</span>
<span className="mt-1 text-sm font-semibold leading-6 text-slate-900">
{processResponseData(response)}
</span>
</div>
@@ -38,7 +38,7 @@ export function ResponseErrorComponent({ questions, responseData, onRetry }: Res
})}
</div>
</div>
<div className="fb-mt-4 fb-flex fb-flex-1 fb-flex-row fb-items-center fb-justify-end fb-space-x-2">
<div className="mt-4 flex flex-1 flex-row items-center justify-end space-x-2">
<SubmitButton
buttonLabel={t("common.retry")}
isLastQuestion={false}

View File

@@ -24,11 +24,11 @@ export function Subheader({ subheader, questionId }: SubheaderProps) {
return (
<label
htmlFor={questionId}
className="fb-text-subheading fb-block fb-break-words fb-text-sm fb-font-normal fb-leading-6"
className="text-subheading block break-words text-sm font-normal leading-6"
data-testid="subheader"
dir="auto">
{isHtml ? (
<span className="fb-htmlbody" dangerouslySetInnerHTML={{ __html: safeHtml }} />
<span className="htmlbody" dangerouslySetInnerHTML={{ __html: safeHtml }} />
) : (
<span>{subheader}</span>
)}

View File

@@ -16,7 +16,7 @@ export function SurveyCloseButton({ onClose, hoverColor, borderRadius }: Readonl
const hoverColorWithOpacity = hoverColor ?? mixColor("#000000", "#ffffff", 0.8);
return (
<div className="fb-z-[1001] fb-flex fb-w-fit fb-items-center">
<div className="z-[1001] flex w-fit items-center">
<button
type="button"
onClick={onClose}
@@ -28,7 +28,7 @@ export function SurveyCloseButton({ onClose, hoverColor, borderRadius }: Readonl
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className={cn(
"fb-text-heading fb-relative focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-offset-2 fb-p-2 fb-h-8 fb-w-8 flex items-center justify-center"
"text-heading relative flex h-8 w-8 items-center justify-center p-2 focus:outline-none focus:ring-2 focus:ring-offset-2"
)}
aria-label={t("common.close_survey")}>
<CloseIcon />

View File

@@ -666,7 +666,7 @@ export function Survey({
return (
<>
{localSurvey.type !== "link" ? (
<div className="fb-flex fb-h-6 fb-justify-end fb-pr-2 fb-pt-2 fb-bg-white">
<div className="flex h-6 justify-end bg-white pr-2 pt-2">
<SurveyCloseButton onClose={onClose} />
</div>
) : null}
@@ -763,19 +763,19 @@ export function Survey({
setHasInteracted={setHasInteracted}>
<div
className={cn(
"fb-no-scrollbar fb-bg-survey-bg fb-flex fb-h-full fb-w-full fb-flex-col fb-justify-between fb-overflow-hidden fb-transition-all fb-duration-1000 fb-ease-in-out",
offset === 0 || cardArrangement === "simple" ? "fb-opacity-100" : "fb-opacity-0"
"no-scrollbar bg-survey-bg flex h-full w-full flex-col justify-between overflow-hidden transition-all duration-1000 ease-in-out",
offset === 0 || cardArrangement === "simple" ? "opacity-100" : "opacity-0"
)}>
<div className={cn("fb-relative")}>
<div className="fb-flex fb-flex-col fb-w-full fb-items-end">
<div className={cn("relative")}>
<div className="flex w-full flex-col items-end">
{showProgressBar ? <ProgressBar survey={localSurvey} questionId={questionId} /> : null}
<div
className={cn(
"fb-relative fb-w-full",
isCloseButtonVisible || isLanguageSwitchVisible ? "fb-h-8" : "fb-h-5"
"relative w-full",
isCloseButtonVisible || isLanguageSwitchVisible ? "h-8" : "h-5"
)}>
<div className={cn("fb-flex fb-items-center fb-justify-end fb-w-full")}>
<div className={cn("flex w-full items-center justify-end")}>
{isLanguageSwitchVisible && (
<LanguageSwitch
survey={localSurvey}
@@ -788,7 +788,7 @@ export function Survey({
/>
)}
{isLanguageSwitchVisible && isCloseButtonVisible && (
<div aria-hidden="true" className="fb-h-5 fb-w-px fb-bg-slate-200 fb-z-[1001]" />
<div aria-hidden="true" className="z-[1001] h-5 w-px bg-slate-200" />
)}
{isCloseButtonVisible && (
@@ -804,16 +804,16 @@ export function Survey({
<div
ref={contentRef}
className={cn(
loadingElement ? "fb-animate-pulse fb-opacity-60" : "",
fullSizeCards ? "" : "fb-my-auto"
loadingElement ? "animate-pulse opacity-60" : "",
fullSizeCards ? "" : "my-auto"
)}>
{content()}
</div>
<div
className={cn(
"fb-flex fb-flex-col fb-justify-center fb-gap-2",
isCloseButtonVisible || isLanguageSwitchVisible ? "fb-p-2" : "fb-p-3"
"flex flex-col justify-center gap-2",
isCloseButtonVisible || isLanguageSwitchVisible ? "p-2" : "p-3"
)}>
{isBrandingEnabled ? <FormbricksBranding /> : null}
{isSpamProtectionEnabled ? <RecaptchaBranding /> : null}

View File

@@ -30,7 +30,7 @@ interface WelcomeCardProps {
function TimerIcon() {
return (
<div className="fb-mr-1">
<div className="mr-1">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
@@ -47,14 +47,14 @@ function TimerIcon() {
function UsersIcon() {
return (
<div className="fb-mr-1">
<div className="mr-1">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="1.5"
stroke="currentColor"
className="fb-h-4 fb-w-4">
className="h-4 w-4">
<path
strokeLinecap="round"
strokeLinejoin="round"
@@ -144,11 +144,7 @@ export function WelcomeCard({
<ScrollableContainer fullSizeCards={fullSizeCards}>
<div>
{fileUrl ? (
<img
src={fileUrl}
className="fb-mb-8 fb-max-h-96 fb-w-1/4 fb-object-contain"
alt={t("common.company_logo")}
/>
<img src={fileUrl} className="mb-8 max-h-96 w-1/4 object-contain" alt={t("common.company_logo")} />
) : null}
<Headline
@@ -163,7 +159,7 @@ export function WelcomeCard({
)}
questionId="welcomeCard"
/>
<div className="fb-mt-4 fb-flex fb-gap-4 fb-pt-4">
<div className="mt-4 flex gap-4 pt-4">
<SubmitButton
buttonLabel={getLocalizedValue(buttonLabel, languageCode)}
isLastQuestion={false}
@@ -180,10 +176,10 @@ export function WelcomeCard({
</div>
{timeToFinish && !showResponseCount ? (
<div
className="fb-items-center fb-text-subheading fb-my-4 fb-flex"
className="text-subheading my-4 flex items-center"
data-testid="fb__surveys__welcome-card__time-display">
<TimerIcon />
<p className="fb-pt-1 fb-text-xs">
<p className="pt-1 text-xs">
<span>
{t("common.takes")} {calculateTimeToComplete()}{" "}
</span>
@@ -191,9 +187,9 @@ export function WelcomeCard({
</div>
) : null}
{showResponseCount && !timeToFinish && responseCount && responseCount > 3 ? (
<div className="fb-items-center fb-text-subheading fb-my-4 fb-flex">
<div className="text-subheading my-4 flex items-center">
<UsersIcon />
<p className="fb-pt-1 fb-text-xs">
<p className="pt-1 text-xs">
<span data-testid="fb__surveys__welcome-card__response-count">
{t("common.people_responded", { count: responseCount })}
</span>
@@ -201,9 +197,9 @@ export function WelcomeCard({
</div>
) : null}
{timeToFinish && showResponseCount ? (
<div className="fb-items-center fb-text-subheading fb-my-4 fb-flex">
<div className="text-subheading my-4 flex items-center">
<TimerIcon />
<p className="fb-pt-1 fb-text-xs" data-testid="fb__surveys__welcome-card__info-text-test">
<p className="pt-1 text-xs" data-testid="fb__surveys__welcome-card__info-text-test">
<span>
{t("common.takes")} {calculateTimeToComplete()}{" "}
</span>

View File

@@ -125,7 +125,7 @@ export function AddressQuestion({
return (
<ScrollableContainer fullSizeCards={fullSizeCards}>
<form key={question.id} onSubmit={handleSubmit} className="fb-w-full" ref={formRef}>
<form key={question.id} onSubmit={handleSubmit} className="w-full" ref={formRef}>
<div>
{isMediaAvailable ? (
<QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} />
@@ -140,7 +140,7 @@ export function AddressQuestion({
questionId={question.id}
/>
<div className="fb-flex fb-flex-col fb-space-y-2 fb-mt-4 fb-w-full">
<div className="mt-4 flex w-full flex-col space-y-2">
{fields.map((field, index) => {
const isFieldRequired = () => {
if (field.required) {
@@ -160,7 +160,7 @@ export function AddressQuestion({
return (
field.show && (
<div className="fb-space-y-1">
<div className="space-y-1">
<Label htmlForId={field.id} text={isFieldRequired() ? `${field.label}*` : field.label} />
<Input
id={field.id}
@@ -181,7 +181,7 @@ export function AddressQuestion({
);
})}
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}

View File

@@ -84,7 +84,7 @@ export function CalQuestion({
onChange({ [question.id]: value });
onSubmit({ [question.id]: value }, updatedttc);
}}
className="fb-w-full">
className="w-full">
<div>
{isMediaAvailable ? (
<QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} />
@@ -99,9 +99,9 @@ export function CalQuestion({
questionId={question.id}
/>
<CalEmbed key={question.id} question={question} onSuccessfulBooking={onSuccessfulBooking} />
{errorMessage ? <span className="fb-text-red-500">{errorMessage}</span> : null}
{errorMessage ? <span className="text-red-500">{errorMessage}</span> : null}
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}

View File

@@ -93,7 +93,7 @@ export function ConsentQuestion({
document.getElementById(`${question.id}-label`)?.focus();
}
}}
className="fb-border-border fb-bg-input-bg fb-text-heading hover:fb-bg-input-bg-selected focus:fb-bg-input-bg-selected focus:fb-ring-brand fb-rounded-custom fb-relative fb-z-10 fb-my-2 fb-flex fb-w-full fb-cursor-pointer fb-items-center fb-border fb-p-4 fb-text-sm focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-offset-2">
className="border-border bg-input-bg text-heading hover:bg-input-bg-selected focus:bg-input-bg-selected focus:ring-brand rounded-custom relative z-10 my-2 flex w-full cursor-pointer items-center border p-4 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2">
<input
tabIndex={-1}
type="checkbox"
@@ -109,15 +109,15 @@ export function ConsentQuestion({
}
}}
checked={value === "accepted"}
className="fb-border-brand fb-text-brand fb-h-4 fb-w-4 fb-border focus:fb-ring-0 focus:fb-ring-offset-0"
className="border-brand text-brand h-4 w-4 border focus:ring-0 focus:ring-offset-0"
aria-labelledby={`${question.id}-label`}
required={question.required}
/>
<span id={`${question.id}-label`} className="fb-ml-3 fb-mr-3 fb-font-medium fb-flex-1" dir="auto">
<span id={`${question.id}-label`} className="ml-3 mr-3 flex-1 font-medium" dir="auto">
{getLocalizedValue(question.label, languageCode)}
</span>
</label>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}

View File

@@ -120,7 +120,7 @@ export function ContactInfoQuestion({
return (
<ScrollableContainer fullSizeCards={fullSizeCards}>
<form key={question.id} onSubmit={handleSubmit} className="fb-w-full" ref={formRef}>
<form key={question.id} onSubmit={handleSubmit} className="w-full" ref={formRef}>
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -132,7 +132,7 @@ export function ContactInfoQuestion({
questionId={question.id}
/>
<div className="fb-flex fb-flex-col fb-space-y-2 fb-mt-4 fb-w-full">
<div className="mt-4 flex w-full flex-col space-y-2">
{fields.map((field, index) => {
const isFieldRequired = () => {
if (field.required) {
@@ -159,7 +159,7 @@ export function ContactInfoQuestion({
return (
field.show && (
<div className="fb-space-y-1">
<div className="space-y-1">
<Label htmlForId={field.id} text={isFieldRequired() ? `${field.label}*` : field.label} />
<Input
id={field.id}
@@ -180,7 +180,7 @@ export function ContactInfoQuestion({
);
})}
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}

View File

@@ -65,8 +65,8 @@ export function CTAQuestion({
subheader={question.subheader ? getLocalizedValue(question.subheader, languageCode) : ""}
questionId={question.id}
/>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-start">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<div className="flex w-full flex-row-reverse justify-start">
<SubmitButton
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}
@@ -98,7 +98,7 @@ export function CTAQuestion({
onSubmit({ [question.id]: "" }, updatedTtcObj);
onChange({ [question.id]: "" });
}}
className="fb-text-heading focus:fb-ring-focus fb-mr-4 fb-flex fb-items-center fb-rounded-md fb-px-3 fb-py-3 fb-text-base fb-font-medium fb-leading-4 hover:fb-opacity-90 focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-offset-2">
className="text-heading focus:ring-focus mr-4 flex items-center rounded-md px-3 py-3 text-base font-medium leading-4 hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-offset-2">
{getLocalizedValue(question.dismissButtonLabel, languageCode) || "Skip"}
</button>
)}

View File

@@ -151,7 +151,7 @@ export function DateQuestion({
setTtc(updatedTtcObj);
onSubmit({ [question.id]: value }, updatedTtcObj);
}}
className="fb-w-full">
className="w-full">
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -162,13 +162,13 @@ export function DateQuestion({
subheader={question.subheader ? getLocalizedValue(question.subheader, languageCode) : ""}
questionId={question.id}
/>
<div id="error-message" className="fb-text-red-600" aria-live="assertive">
<div id="error-message" className="text-red-600" aria-live="assertive">
<span>{errorMessage}</span>
</div>
<div
className={cn("fb-mt-4 fb-w-full", errorMessage && "fb-rounded-lg fb-border-2 fb-border-red-500")}
className={cn("mt-4 w-full", errorMessage && "rounded-lg border-2 border-red-500")}
id="date-picker-root">
<div className="fb-relative">
<div className="relative">
{!datePickerOpen && (
<button
onClick={() => {
@@ -185,14 +185,14 @@ export function DateQuestion({
: t("common.select_a_date")
}
aria-describedby={errorMessage ? "error-message" : undefined}
className="focus:fb-outline-brand fb-bg-input-bg hover:fb-bg-input-bg-selected fb-border-border fb-text-heading fb-rounded-custom fb-relative fb-flex fb-h-[12dvh] fb-w-full fb-cursor-pointer fb-appearance-none fb-items-center fb-justify-center fb-border fb-text-left fb-text-base fb-font-normal">
<div className="fb-flex fb-items-center fb-gap-2">
className="focus:outline-brand bg-input-bg hover:bg-input-bg-selected border-border text-heading rounded-custom relative flex h-[12dvh] w-full cursor-pointer appearance-none items-center justify-center border text-left text-base font-normal">
<div className="flex items-center gap-2">
{selectedDate ? (
<div className="fb-flex fb-items-center fb-gap-2">
<div className="flex items-center gap-2">
<CalendarCheckIcon /> <span>{formattedDate}</span>
</div>
) : (
<div className="fb-flex fb-items-center fb-gap-2">
<div className="flex items-center gap-2">
<CalendarIcon /> <span>{t("common.select_a_date")}</span>
</div>
)}
@@ -225,13 +225,13 @@ export function DateQuestion({
monthPlaceholder="MM"
yearPlaceholder="YYYY"
format={question.format ?? "M-d-y"}
className={`dp-input-root fb-rounded-custom wrapper-hide ${!datePickerOpen ? "" : "fb-h-[46dvh] sm:fb-h-[34dvh]"} ${hideInvalid ? "hide-invalid" : ""} `}
className={`dp-input-root rounded-custom wrapper-hide ${!datePickerOpen ? "" : "h-[46dvh] sm:h-[34dvh]"} ${hideInvalid ? "hide-invalid" : ""} `}
calendarProps={{
className:
"calendar-root !fb-text-heading !fb-bg-input-bg fb-border fb-border-border fb-rounded-custom fb-p-3 fb-h-[46dvh] sm:fb-h-[33dvh] fb-overflow-auto",
"calendar-root !text-heading !bg-input-bg border border-border rounded-custom p-3 h-[46dvh] sm:h-[33dvh] overflow-auto",
tileClassName: ({ date }: { date: Date }) => {
const baseClass =
"hover:fb-bg-input-bg-selected fb-rounded-custom fb-h-9 fb-p-0 fb-mt-1 fb-font-normal aria-selected:fb-opacity-100 focus:fb-ring-2 focus:fb-bg-slate-200";
"hover:bg-input-bg-selected rounded-custom h-9 p-0 mt-1 font-normal aria-selected:opacity-100 focus:ring-2 focus:bg-slate-200";
// active date class (check first to take precedence over today's date)
if (
selectedDate &&
@@ -239,7 +239,7 @@ export function DateQuestion({
date.getMonth() === selectedDate.getMonth() &&
date.getFullYear() === selectedDate.getFullYear()
) {
return `${baseClass} !fb-bg-brand !fb-border-border-highlight !fb-text-calendar-tile`;
return `${baseClass} !bg-brand !border-border-highlight !text-calendar-tile`;
}
// today's date class
if (
@@ -247,10 +247,10 @@ export function DateQuestion({
date.getMonth() === new Date().getMonth() &&
date.getFullYear() === new Date().getFullYear()
) {
return `${baseClass} !fb-bg-brand !fb-opacity-50 !fb-border-border-highlight !fb-text-calendar-tile focus:fb-ring-2 focus:fb-bg-slate-200`;
return `${baseClass} !bg-brand !opacity-50 !border-border-highlight !text-calendar-tile focus:ring-2 focus:bg-slate-200`;
}
return `${baseClass} !fb-text-heading`;
return `${baseClass} !text-heading`;
},
formatShortWeekday: (_: any, date: Date) => {
return date.toLocaleDateString("en-US", { weekday: "short" }).slice(0, 2);
@@ -271,7 +271,7 @@ export function DateQuestion({
/>
</div>
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
isLastQuestion={isLastQuestion}

View File

@@ -76,7 +76,7 @@ export function FileUploadQuestion({
onSubmit({ [question.id]: "skipped" }, updatedTtcObj);
}
}}
className="fb-w-full">
className="w-full">
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -105,7 +105,7 @@ export function FileUploadQuestion({
: {})}
{...(question.maxSizeInMB ? { maxSizeInMB: question.maxSizeInMB } : {})}
/>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}

View File

@@ -116,7 +116,7 @@ export function MatrixQuestion({
<th
key={index}
scope="col"
className="fb-text-heading fb-max-w-40 fb-break-words fb-px-4 fb-py-2 fb-font-normal"
className="text-heading max-w-40 break-words px-4 py-2 font-normal"
dir="auto">
{getLocalizedValue(column.label, languageCode)}
</th>
@@ -126,7 +126,7 @@ export function MatrixQuestion({
return (
<ScrollableContainer fullSizeCards={fullSizeCards}>
<form key={question.id} onSubmit={handleSubmit} className="fb-w-full">
<form key={question.id} onSubmit={handleSubmit} className="w-full">
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -134,20 +134,20 @@ export function MatrixQuestion({
required={question.required}
/>
<Subheader subheader={getLocalizedValue(question.subheader, languageCode)} questionId={question.id} />
<div className="fb-overflow-x-auto fb-py-4">
<table className="fb-no-scrollbar fb-min-w-full fb-table-auto fb-border-collapse fb-text-sm">
<div className="overflow-x-auto py-4">
<table className="no-scrollbar min-w-full table-auto border-collapse text-sm">
<thead>
<tr>
<th className="fb-px-4 fb-py-2" />
<th className="px-4 py-2" />
{columnsHeaders}
</tr>
</thead>
<tbody>
{questionRows.map((row, rowIndex) => (
<tr key={`row-${rowIndex.toString()}`} className={rowIndex % 2 === 0 ? "fb-bg-input-bg" : ""}>
<tr key={`row-${rowIndex.toString()}`} className={rowIndex % 2 === 0 ? "bg-input-bg" : ""}>
<th
scope="row"
className="fb-text-heading fb-rounded-l-custom fb-max-w-40 fb-break-words fb-pr-4 fb-pl-2 fb-py-2 fb-text-left fb-min-w-[20%] fb-font-semibold"
className="text-heading rounded-l-custom min-w-[20%] max-w-40 break-words py-2 pl-2 pr-4 text-left font-semibold"
dir="auto">
{getLocalizedValue(row.label, languageCode)}
</th>
@@ -155,7 +155,7 @@ export function MatrixQuestion({
<td
key={`column-${columnIndex.toString()}`}
tabIndex={isCurrent ? 0 : -1}
className={`fb-outline-brand fb-px-4 fb-py-2 fb-text-slate-800 ${columnIndex === question.columns.length - 1 ? "fb-rounded-r-custom" : ""}`}
className={`outline-brand px-4 py-2 text-slate-800 ${columnIndex === question.columns.length - 1 ? "rounded-r-custom" : ""}`}
onClick={() => {
handleSelect(
getLocalizedValue(column.label, languageCode),
@@ -172,7 +172,7 @@ export function MatrixQuestion({
}
}}
dir="auto">
<div className="fb-flex fb-items-center fb-justify-center fb-p-2">
<div className="flex items-center justify-center p-2">
<input
dir="auto"
type="radio"
@@ -191,7 +191,7 @@ export function MatrixQuestion({
column.label,
languageCode
)}`}
className="fb-border-brand fb-text-brand fb-h-5 fb-w-5 fb-border focus:fb-ring-0 focus:fb-ring-offset-0"
className="border-brand text-brand h-5 w-5 border focus:ring-0 focus:ring-offset-0"
/>
</div>
</td>
@@ -201,7 +201,7 @@ export function MatrixQuestion({
</tbody>
</table>
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}
isLastQuestion={isLastQuestion}

View File

@@ -115,7 +115,7 @@ export function MultipleChoiceMultiQuestion({
// Common label className for all choice types
const baseLabelClassName =
"fb-text-heading focus-within:fb-border-brand fb-bg-input-bg focus-within:fb-bg-input-bg-selected hover:fb-bg-input-bg-selected fb-rounded-custom fb-relative fb-flex fb-cursor-pointer fb-flex-col fb-border fb-p-4 focus:fb-outline-none";
"text-heading focus-within:border-brand bg-input-bg focus-within:bg-input-bg-selected hover:bg-input-bg-selected rounded-custom relative flex cursor-pointer flex-col border p-4 focus:outline-none";
useEffect(() => {
// Scroll to the bottom of choices container and focus on 'otherSpecify' input when 'otherSelected' is true
@@ -177,7 +177,7 @@ export function MultipleChoiceMultiQuestion({
setTtc(updatedTtcObj);
onSubmit({ [question.id]: newValue }, updatedTtcObj);
}}
className="fb-w-full">
className="w-full">
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -188,10 +188,10 @@ export function MultipleChoiceMultiQuestion({
subheader={question.subheader ? getLocalizedValue(question.subheader, languageCode) : ""}
questionId={question.id}
/>
<div className="fb-mt-4">
<div className="mt-4">
<fieldset>
<legend className="fb-sr-only">Options</legend>
<div className="fb-bg-survey-bg fb-relative fb-space-y-2" ref={choicesContainerRef}>
<legend className="sr-only">Options</legend>
<div className="bg-survey-bg relative space-y-2" ref={choicesContainerRef}>
{questionChoices.map((choice, idx) => {
if (!choice || choice.id === "other" || choice.id === "none") return;
return (
@@ -200,9 +200,9 @@ export function MultipleChoiceMultiQuestion({
tabIndex={isCurrent ? 0 : -1}
className={cn(
value.includes(getLocalizedValue(choice.label, languageCode))
? "fb-border-brand fb-bg-input-bg-selected fb-z-10"
: "fb-border-border fb-bg-input-bg",
isNoneSelected ? "fb-opacity-50" : "",
? "border-brand bg-input-bg-selected z-10"
: "border-border bg-input-bg",
isNoneSelected ? "opacity-50" : "",
baseLabelClassName
)}
onKeyDown={(e) => {
@@ -213,7 +213,7 @@ export function MultipleChoiceMultiQuestion({
}
}}
autoFocus={idx === 0 && autoFocusEnabled}>
<span className="fb-flex fb-items-center fb-text-sm">
<span className="flex items-center text-sm">
<input
type="checkbox"
dir={dir}
@@ -221,7 +221,7 @@ export function MultipleChoiceMultiQuestion({
name={question.id}
tabIndex={-1}
value={getLocalizedValue(choice.label, languageCode)}
className="fb-border-brand fb-text-brand fb-h-4 fb-w-4 fb-flex-shrink-0 fb-border focus:fb-ring-0 focus:fb-ring-offset-0"
className="border-brand text-brand h-4 w-4 flex-shrink-0 border focus:ring-0 focus:ring-offset-0"
aria-labelledby={`${choice.id}-label`}
disabled={isNoneSelected}
onChange={(e) => {
@@ -237,7 +237,7 @@ export function MultipleChoiceMultiQuestion({
}
required={getIsRequired()}
/>
<span id={`${choice.id}-label`} className="fb-mx-3 fb-grow fb-font-medium" dir="auto">
<span id={`${choice.id}-label`} className="mx-3 grow font-medium" dir="auto">
{getLocalizedValue(choice.label, languageCode)}
</span>
</span>
@@ -248,10 +248,8 @@ export function MultipleChoiceMultiQuestion({
<label
tabIndex={isCurrent ? 0 : -1}
className={cn(
otherSelected
? "fb-border-brand fb-bg-input-bg-selected fb-z-10"
: "fb-border-border fb-bg-input-bg",
isNoneSelected ? "fb-opacity-50" : "",
otherSelected ? "border-brand bg-input-bg-selected z-10" : "border-border bg-input-bg",
isNoneSelected ? "opacity-50" : "",
baseLabelClassName
)}
onKeyDown={(e) => {
@@ -262,7 +260,7 @@ export function MultipleChoiceMultiQuestion({
document.getElementById(otherOption.id)?.click();
}
}}>
<span className="fb-flex fb-items-center fb-text-sm">
<span className="flex items-center text-sm">
<input
type="checkbox"
dir={dir}
@@ -270,7 +268,7 @@ export function MultipleChoiceMultiQuestion({
id={otherOption.id}
name={question.id}
value={getLocalizedValue(otherOption.label, languageCode)}
className="fb-border-brand fb-text-brand fb-h-4 fb-w-4 fb-flex-shrink-0 fb-border focus:fb-ring-0 focus:fb-ring-offset-0"
className="border-brand text-brand h-4 w-4 flex-shrink-0 border focus:ring-0 focus:ring-offset-0"
aria-labelledby={`${otherOption.id}-label`}
disabled={isNoneSelected}
onChange={() => {
@@ -286,10 +284,7 @@ export function MultipleChoiceMultiQuestion({
}}
checked={otherSelected}
/>
<span
id={`${otherOption.id}-label`}
className="fb-ml-3 fb-mr-3 fb-grow fb-font-medium"
dir="auto">
<span id={`${otherOption.id}-label`} className="ml-3 mr-3 grow font-medium" dir="auto">
{getLocalizedValue(otherOption.label, languageCode)}
</span>
</span>
@@ -306,7 +301,7 @@ export function MultipleChoiceMultiQuestion({
onChange={(e) => {
setOtherValue(e.currentTarget.value);
}}
className="placeholder:fb-text-placeholder fb-border-border fb-bg-survey-bg fb-text-heading focus:fb-ring-focus fb-rounded-custom fb-mt-3 fb-flex fb-h-10 fb-w-full fb-border fb-px-3 fb-py-2 fb-text-sm focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-offset-2 disabled:fb-cursor-not-allowed disabled:fb-opacity-50"
className="placeholder:text-placeholder border-border bg-survey-bg text-heading focus:ring-focus rounded-custom mt-3 flex h-10 w-full border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
placeholder={
getLocalizedValue(question.otherOptionPlaceholder, languageCode).length > 0
? getLocalizedValue(question.otherOptionPlaceholder, languageCode)
@@ -331,9 +326,7 @@ export function MultipleChoiceMultiQuestion({
<label
tabIndex={isCurrent ? 0 : -1}
className={cn(
isNoneSelected
? "fb-border-brand fb-bg-input-bg-selected fb-z-10"
: "fb-border-border fb-bg-input-bg",
isNoneSelected ? "border-brand bg-input-bg-selected z-10" : "border-border bg-input-bg",
baseLabelClassName
)}
onKeyDown={(e) => {
@@ -342,7 +335,7 @@ export function MultipleChoiceMultiQuestion({
document.getElementById(noneOption.id)?.click();
}
}}>
<span className="fb-flex fb-items-center fb-text-sm">
<span className="flex items-center text-sm">
<input
type="checkbox"
dir={dir}
@@ -350,7 +343,7 @@ export function MultipleChoiceMultiQuestion({
id={noneOption.id}
name={question.id}
value={getLocalizedValue(noneOption.label, languageCode)}
className="fb-border-brand fb-text-brand fb-h-4 fb-w-4 fb-flex-shrink-0 fb-border focus:fb-ring-0 focus:fb-ring-offset-0"
className="border-brand text-brand h-4 w-4 flex-shrink-0 border focus:ring-0 focus:ring-offset-0"
aria-labelledby={`${noneOption.id}-label`}
onChange={(e) => {
if ((e.target as HTMLInputElement).checked) {
@@ -363,10 +356,7 @@ export function MultipleChoiceMultiQuestion({
}}
checked={isNoneSelected}
/>
<span
id={`${noneOption.id}-label`}
className="fb-ml-3 fb-mr-3 fb-grow fb-font-medium"
dir="auto">
<span id={`${noneOption.id}-label`} className="ml-3 mr-3 grow font-medium" dir="auto">
{getLocalizedValue(noneOption.label, languageCode)}
</span>
</span>
@@ -375,7 +365,7 @@ export function MultipleChoiceMultiQuestion({
</div>
</fieldset>
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}

View File

@@ -121,7 +121,7 @@ export function MultipleChoiceSingleQuestion({
setTtc(updatedTtcObj);
onSubmit({ [question.id]: value }, updatedTtcObj);
}}
className="fb-w-full">
className="w-full">
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -132,14 +132,11 @@ export function MultipleChoiceSingleQuestion({
subheader={question.subheader ? getLocalizedValue(question.subheader, languageCode) : ""}
questionId={question.id}
/>
<div className="fb-mt-4">
<div className="mt-4">
<fieldset>
<legend className="fb-sr-only">Options</legend>
<legend className="sr-only">Options</legend>
<div
className="fb-bg-survey-bg fb-relative fb-space-y-2"
role="radiogroup"
ref={choicesContainerRef}>
<div className="bg-survey-bg relative space-y-2" role="radiogroup" ref={choicesContainerRef}>
{questionChoices.map((choice, idx) => {
if (!choice || choice.id === "other" || choice.id === "none") return;
return (
@@ -148,9 +145,9 @@ export function MultipleChoiceSingleQuestion({
tabIndex={isCurrent ? 0 : -1}
className={cn(
value === getLocalizedValue(choice.label, languageCode)
? "fb-border-brand fb-bg-input-bg-selected fb-z-10"
: "fb-border-border",
"fb-text-heading fb-bg-input-bg focus-within:fb-border-brand focus-within:fb-bg-input-bg-selected hover:fb-bg-input-bg-selected fb-rounded-custom fb-relative fb-flex fb-cursor-pointer fb-flex-col fb-border fb-p-4 focus:fb-outline-none"
? "border-brand bg-input-bg-selected z-10"
: "border-border",
"text-heading bg-input-bg focus-within:border-brand focus-within:bg-input-bg-selected hover:bg-input-bg-selected rounded-custom relative flex cursor-pointer flex-col border p-4 focus:outline-none"
)}
onKeyDown={(e) => {
// Accessibility: if spacebar was pressed pass this down to the input
@@ -161,7 +158,7 @@ export function MultipleChoiceSingleQuestion({
}
}}
autoFocus={idx === 0 && autoFocusEnabled}>
<span className="fb-flex fb-items-center fb-text-sm">
<span className="flex items-center text-sm">
<input
tabIndex={-1}
type="radio"
@@ -169,7 +166,7 @@ export function MultipleChoiceSingleQuestion({
name={question.id}
value={getLocalizedValue(choice.label, languageCode)}
dir={dir}
className="fb-border-brand fb-text-brand fb-h-4 fb-w-4 fb-flex-shrink-0 fb-border focus:fb-ring-0 focus:fb-ring-offset-0"
className="border-brand text-brand h-4 w-4 flex-shrink-0 border focus:ring-0 focus:ring-offset-0"
aria-labelledby={`${choice.id}-label`}
onClick={() => {
const choiceValue = getLocalizedValue(choice.label, languageCode);
@@ -183,10 +180,7 @@ export function MultipleChoiceSingleQuestion({
checked={value === getLocalizedValue(choice.label, languageCode)}
required={question.required ? idx === 0 : undefined}
/>
<span
id={`${choice.id}-label`}
className="fb-ml-3 fb-mr-3 fb-grow fb-font-medium"
dir="auto">
<span id={`${choice.id}-label`} className="ml-3 mr-3 grow font-medium" dir="auto">
{getLocalizedValue(choice.label, languageCode)}
</span>
</span>
@@ -198,9 +192,9 @@ export function MultipleChoiceSingleQuestion({
tabIndex={isCurrent ? 0 : -1}
className={cn(
value === getLocalizedValue(otherOption.label, languageCode)
? "fb-border-brand fb-bg-input-bg-selected fb-z-10"
: "fb-border-border",
"fb-text-heading focus-within:fb-border-brand fb-bg-input-bg focus-within:fb-bg-input-bg-selected hover:fb-bg-input-bg-selected fb-rounded-custom fb-relative fb-flex fb-cursor-pointer fb-flex-col fb-border fb-p-4 focus:fb-outline-none"
? "border-brand bg-input-bg-selected z-10"
: "border-border",
"text-heading focus-within:border-brand bg-input-bg focus-within:bg-input-bg-selected hover:bg-input-bg-selected rounded-custom relative flex cursor-pointer flex-col border p-4 focus:outline-none"
)}
onKeyDown={(e) => {
// Accessibility: if spacebar was pressed pass this down to the input
@@ -210,7 +204,7 @@ export function MultipleChoiceSingleQuestion({
document.getElementById(otherOption.id)?.focus();
}
}}>
<span className="fb-flex fb-items-center fb-text-sm">
<span className="flex items-center text-sm">
<input
tabIndex={-1}
dir={dir}
@@ -218,7 +212,7 @@ export function MultipleChoiceSingleQuestion({
id={otherOption.id}
name={question.id}
value={getLocalizedValue(otherOption.label, languageCode)}
className="fb-border-brand fb-text-brand fb-h-4 fb-w-4 fb-flex-shrink-0 fb-border focus:fb-ring-0 focus:fb-ring-offset-0"
className="border-brand text-brand h-4 w-4 flex-shrink-0 border focus:ring-0 focus:ring-offset-0"
aria-labelledby={`${otherOption.id}-label`}
onClick={() => {
if (otherSelected && !question.required) {
@@ -231,10 +225,7 @@ export function MultipleChoiceSingleQuestion({
}}
checked={otherSelected}
/>
<span
id={`${otherOption.id}-label`}
className="fb-ml-3 fb-mr-3 fb-grow fb-font-medium"
dir="auto">
<span id={`${otherOption.id}-label`} className="ml-3 mr-3 grow font-medium" dir="auto">
{getLocalizedValue(otherOption.label, languageCode)}
</span>
</span>
@@ -249,7 +240,7 @@ export function MultipleChoiceSingleQuestion({
onChange={(e) => {
onChange({ [question.id]: e.currentTarget.value });
}}
className="placeholder:fb-text-placeholder fb-border-border fb-bg-survey-bg fb-text-heading focus:fb-ring-focus fb-rounded-custom fb-mt-3 fb-flex fb-h-10 fb-w-full fb-border fb-px-3 fb-py-2 fb-text-sm focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-offset-2 disabled:fb-cursor-not-allowed disabled:fb-opacity-50"
className="placeholder:text-placeholder border-border bg-survey-bg text-heading focus:ring-focus rounded-custom mt-3 flex h-10 w-full border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
placeholder={
getLocalizedValue(question.otherOptionPlaceholder, languageCode).length > 0
? getLocalizedValue(question.otherOptionPlaceholder, languageCode)
@@ -267,9 +258,9 @@ export function MultipleChoiceSingleQuestion({
tabIndex={isCurrent ? 0 : -1}
className={cn(
value === getLocalizedValue(noneOption.label, languageCode)
? "fb-border-brand fb-bg-input-bg-selected fb-z-10"
: "fb-border-border",
"fb-text-heading focus-within:fb-border-brand fb-bg-input-bg focus-within:fb-bg-input-bg-selected hover:fb-bg-input-bg-selected fb-rounded-custom fb-relative fb-flex fb-cursor-pointer fb-flex-col fb-border fb-p-4 focus:fb-outline-none"
? "border-brand bg-input-bg-selected z-10"
: "border-border",
"text-heading focus-within:border-brand bg-input-bg focus-within:bg-input-bg-selected hover:bg-input-bg-selected rounded-custom relative flex cursor-pointer flex-col border p-4 focus:outline-none"
)}
onKeyDown={(e) => {
// Accessibility: if spacebar was pressed pass this down to the input
@@ -279,7 +270,7 @@ export function MultipleChoiceSingleQuestion({
document.getElementById(noneOption.id)?.focus();
}
}}>
<span className="fb-flex fb-items-center fb-text-sm">
<span className="flex items-center text-sm">
<input
tabIndex={-1}
dir={dir}
@@ -287,7 +278,7 @@ export function MultipleChoiceSingleQuestion({
id={noneOption.id}
name={question.id}
value={getLocalizedValue(noneOption.label, languageCode)}
className="fb-border-brand fb-text-brand fb-h-4 fb-w-4 fb-flex-shrink-0 fb-border focus:fb-ring-0 focus:fb-ring-offset-0"
className="border-brand text-brand h-4 w-4 flex-shrink-0 border focus:ring-0 focus:ring-offset-0"
aria-labelledby={`${noneOption.id}-label`}
onClick={() => {
const noneValue = getLocalizedValue(noneOption.label, languageCode);
@@ -300,10 +291,7 @@ export function MultipleChoiceSingleQuestion({
}}
checked={value === getLocalizedValue(noneOption.label, languageCode)}
/>
<span
id={`${noneOption.id}-label`}
className="fb-ml-3 fb-mr-3 fb-grow fb-font-medium"
dir="auto">
<span id={`${noneOption.id}-label`} className="ml-3 mr-3 grow font-medium" dir="auto">
{getLocalizedValue(noneOption.label, languageCode)}
</span>
</span>
@@ -312,7 +300,7 @@ export function MultipleChoiceSingleQuestion({
</div>
</fieldset>
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}

View File

@@ -66,9 +66,9 @@ export function NPSQuestion({
};
const getNPSOptionColor = (idx: number) => {
if (idx > 8) return "fb-bg-emerald-100";
if (idx > 6) return "fb-bg-orange-100";
return "fb-bg-rose-100";
if (idx > 8) return "bg-emerald-100";
if (idx > 6) return "bg-orange-100";
return "bg-rose-100";
};
return (
@@ -91,10 +91,10 @@ export function NPSQuestion({
subheader={question.subheader ? getLocalizedValue(question.subheader, languageCode) : ""}
questionId={question.id}
/>
<div className="fb-my-4">
<div className="my-4">
<fieldset>
<legend className="fb-sr-only">Options</legend>
<div className="fb-flex">
<legend className="sr-only">Options</legend>
<div className="flex">
{Array.from({ length: 11 }, (_, i) => i).map((number, idx) => {
return (
<label
@@ -122,19 +122,17 @@ export function NPSQuestion({
}}
className={cn(
value === number
? "fb-border-border-highlight fb-bg-accent-selected-bg fb-z-10 fb-border"
: "fb-border-border",
"fb-text-heading focus:fb-border-brand fb-relative fb-h-10 fb-flex-1 fb-cursor-pointer fb-overflow-hidden fb-border-b fb-border-l fb-border-t fb-text-center fb-text-sm focus:fb-border-2 focus:fb-outline-none",
question.isColorCodingEnabled ? "fb-h-[46px] fb-leading-[3.5em]" : "fb-h fb-leading-10",
hoveredNumber === number ? "fb-bg-accent-bg" : "",
? "border-border-highlight bg-accent-selected-bg z-10 border"
: "border-border",
"text-heading focus:border-brand relative h-10 flex-1 cursor-pointer overflow-hidden border-b border-l border-t text-center text-sm focus:border-2 focus:outline-none",
question.isColorCodingEnabled ? "h-[46px] leading-[3.5em]" : "h leading-10",
hoveredNumber === number ? "bg-accent-bg" : "",
dir === "rtl"
? "first:fb-rounded-r-custom first:fb-border-r last:fb-rounded-l-custom last:fb-border-l"
: "first:fb-rounded-l-custom first:fb-border-l last:fb-rounded-r-custom last:fb-border-r"
? "first:rounded-r-custom last:rounded-l-custom first:border-r last:border-l"
: "first:rounded-l-custom last:rounded-r-custom first:border-l last:border-r"
)}>
{question.isColorCodingEnabled ? (
<div
className={`fb-absolute fb-left-0 fb-top-0 fb-h-[6px] fb-w-full ${getNPSOptionColor(idx)}`}
/>
<div className={`absolute left-0 top-0 h-[6px] w-full ${getNPSOptionColor(idx)}`} />
) : null}
<input
type="radio"
@@ -142,7 +140,7 @@ export function NPSQuestion({
name="nps"
value={number}
checked={value === number}
className="fb-absolute fb-left-0 fb-h-full fb-w-full fb-cursor-pointer fb-opacity-0"
className="absolute left-0 h-full w-full cursor-pointer opacity-0"
onClick={() => {
handleClick(number);
}}
@@ -154,17 +152,17 @@ export function NPSQuestion({
);
})}
</div>
<div className="fb-text-subheading fb-mt-2 fb-flex fb-justify-between fb-px-1.5 fb-text-xs fb-leading-6 fb-gap-8">
<p dir="auto" className="fb-max-w-[50%]">
<div className="text-subheading mt-2 flex justify-between gap-8 px-1.5 text-xs leading-6">
<p dir="auto" className="max-w-[50%]">
{getLocalizedValue(question.lowerLabel, languageCode)}
</p>
<p dir="auto" className="fb-max-w-[50%]">
<p dir="auto" className="max-w-[50%]">
{getLocalizedValue(question.upperLabel, languageCode)}
</p>
</div>
</fieldset>
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
{question.required ? (
<div></div>
) : (

View File

@@ -112,7 +112,7 @@ export function OpenTextQuestion({
return (
<ScrollableContainer fullSizeCards={fullSizeCards}>
<form key={question.id} onSubmit={handleOnSubmit} className="fb-w-full">
<form key={question.id} onSubmit={handleOnSubmit} className="w-full">
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -123,7 +123,7 @@ export function OpenTextQuestion({
subheader={question.subheader ? getLocalizedValue(question.subheader, languageCode) : ""}
questionId={question.id}
/>
<div className="fb-mt-4">
<div className="mt-4">
{question.longAnswer === false ? (
<input
ref={inputRef as RefObject<HTMLInputElement>}
@@ -142,7 +142,7 @@ export function OpenTextQuestion({
handleInputChange(input.value);
input.setCustomValidity("");
}}
className="fb-border-border placeholder:fb-text-placeholder fb-text-subheading focus:fb-border-brand fb-bg-input-bg fb-rounded-custom fb-block fb-w-full fb-border fb-p-2 fb-shadow-sm focus:fb-outline-none focus:fb-ring-0 sm:fb-text-sm"
className="border-border placeholder:text-placeholder text-subheading focus:border-brand bg-input-bg rounded-custom block w-full border p-2 shadow-sm focus:outline-none focus:ring-0 sm:text-sm"
pattern={question.inputType === "phone" ? "^[0-9+][0-9+\\- ]*[0-9]$" : ".*"}
title={
question.inputType === "phone"
@@ -178,7 +178,7 @@ export function OpenTextQuestion({
onInput={(e) => {
handleInputChange(e.currentTarget.value);
}}
className="fb-border-border placeholder:fb-text-placeholder fb-bg-input-bg fb-text-subheading focus:fb-border-brand fb-rounded-custom fb-block fb-w-full fb-border fb-p-2 fb-shadow-sm focus:fb-ring-0 sm:fb-text-sm"
className="border-border placeholder:text-placeholder bg-input-bg text-subheading focus:border-brand rounded-custom block w-full border p-2 shadow-sm focus:ring-0 sm:text-sm"
title={
question.inputType === "phone" ? t("errors.please_enter_a_valid_phone_number") : undefined
}
@@ -188,12 +188,12 @@ export function OpenTextQuestion({
)}
{question.inputType === "text" && question.charLimit?.max !== undefined && (
<span
className={`fb-text-xs ${currentLength >= question.charLimit?.max ? "fb-text-red-500 font-semibold" : "text-neutral-400"}`}>
className={`text-xs ${currentLength >= question.charLimit?.max ? "font-semibold text-red-500" : "text-neutral-400"}`}>
{currentLength}/{question.charLimit?.max}
</span>
)}
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}

View File

@@ -112,7 +112,7 @@ export function PictureSelectionQuestion({
setTtc(updatedTtcObj);
onSubmit({ [question.id]: value }, updatedTtcObj);
}}
className="fb-w-full">
className="w-full">
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -123,12 +123,12 @@ export function PictureSelectionQuestion({
subheader={question.subheader ? getLocalizedValue(question.subheader, languageCode) : ""}
questionId={question.id}
/>
<div className="fb-mt-4">
<div className="mt-4">
<fieldset>
<legend className="fb-sr-only">{t("common.options")}</legend>
<div className="fb-bg-survey-bg fb-relative fb-grid fb-grid-cols-1 sm:fb-grid-cols-2 fb-gap-4">
<legend className="sr-only">{t("common.options")}</legend>
<div className="bg-survey-bg relative grid grid-cols-1 gap-4 sm:grid-cols-2">
{questionChoices.map((choice) => (
<div className="fb-relative" key={choice.id}>
<div className="relative" key={choice.id}>
<button
type="button"
tabIndex={isCurrent ? 0 : -1}
@@ -144,21 +144,21 @@ export function PictureSelectionQuestion({
handleChange(choice.id);
}}
className={cn(
"fb-relative fb-w-full fb-cursor-pointer fb-overflow-hidden fb-border fb-rounded-custom focus-visible:fb-outline-none focus-visible:fb-ring-2 focus-visible:fb-ring-brand focus-visible:fb-ring-offset-2 fb-aspect-[4/3] fb-min-h-[7rem] fb-max-h-[50vh] group/image",
"rounded-custom focus-visible:ring-brand group/image relative aspect-[4/3] max-h-[50vh] min-h-[7rem] w-full cursor-pointer overflow-hidden border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
Array.isArray(value) && value.includes(choice.id)
? "fb-border-brand fb-text-brand fb-z-10 fb-border-4 fb-shadow-sm"
? "border-brand text-brand z-10 border-4 shadow-sm"
: ""
)}>
{loadingImages[choice.id] && (
<div className="fb-absolute fb-inset-0 fb-flex fb-h-full fb-w-full fb-animate-pulse fb-items-center fb-justify-center fb-rounded-md fb-bg-slate-200" />
<div className="absolute inset-0 flex h-full w-full animate-pulse items-center justify-center rounded-md bg-slate-200" />
)}
<img
src={choice.imageUrl}
id={choice.id}
alt={getOriginalFileNameFromUrl(choice.imageUrl)}
className={cn(
"fb-h-full fb-w-full fb-object-cover",
loadingImages[choice.id] ? "fb-opacity-0" : ""
"h-full w-full object-cover",
loadingImages[choice.id] ? "opacity-0" : ""
)}
onLoad={() => {
setLoadingImages((prev) => ({ ...prev, [choice.id]: false }));
@@ -175,9 +175,9 @@ export function PictureSelectionQuestion({
tabIndex={-1}
checked={value.includes(choice.id)}
className={cn(
"fb-border-border fb-rounded-custom fb-pointer-events-none fb-absolute fb-top-2 fb-z-20 fb-h-5 fb-w-5 fb-border",
value.includes(choice.id) ? "fb-border-brand fb-text-brand" : "",
dir === "rtl" ? "fb-left-2" : "fb-right-2"
"border-border rounded-custom pointer-events-none absolute top-2 z-20 h-5 w-5 border",
value.includes(choice.id) ? "border-brand text-brand" : "",
dir === "rtl" ? "left-2" : "right-2"
)}
required={question.required && value.length === 0}
/>
@@ -189,9 +189,9 @@ export function PictureSelectionQuestion({
tabIndex={-1}
checked={value.includes(choice.id)}
className={cn(
"fb-border-border fb-pointer-events-none fb-absolute fb-top-2 fb-z-20 fb-h-5 fb-w-5 fb-rounded-full fb-border",
value.includes(choice.id) ? "fb-border-brand fb-text-brand" : "",
dir === "rtl" ? "fb-left-2" : "fb-right-2"
"border-border pointer-events-none absolute top-2 z-20 h-5 w-5 rounded-full border",
value.includes(choice.id) ? "border-brand text-brand" : "",
dir === "rtl" ? "left-2" : "right-2"
)}
required={question.required && value.length ? false : question.required}
/>
@@ -207,10 +207,10 @@ export function PictureSelectionQuestion({
e.stopPropagation();
}}
className={cn(
"fb-absolute fb-bottom-4 fb-flex fb-items-center fb-gap-2 fb-whitespace-nowrap fb-rounded-md fb-bg-slate-800 fb-bg-opacity-40 fb-p-1.5 fb-text-white fb-backdrop-blur-lg fb-transition fb-duration-300 fb-ease-in-out hover:fb-bg-opacity-65 group-hover/image:fb-opacity-100 fb-z-20",
dir === "rtl" ? "fb-left-2" : "fb-right-2"
"absolute bottom-4 z-20 flex items-center gap-2 whitespace-nowrap rounded-md bg-slate-800 bg-opacity-40 p-1.5 text-white backdrop-blur-lg transition duration-300 ease-in-out hover:bg-opacity-65 group-hover/image:opacity-100",
dir === "rtl" ? "left-2" : "right-2"
)}>
<span className="fb-sr-only">{t("common.open_in_new_tab")}</span>
<span className="sr-only">{t("common.open_in_new_tab")}</span>
<ImageDownIcon />
</a>
</div>
@@ -218,7 +218,7 @@ export function PictureSelectionQuestion({
</div>
</fieldset>
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}

View File

@@ -159,7 +159,7 @@ export function RankingQuestion({
return (
<ScrollableContainer ref={scrollableRef} fullSizeCards={fullSizeCards}>
<form onSubmit={handleSubmit} className="fb-w-full">
<form onSubmit={handleSubmit} className="w-full">
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -170,10 +170,10 @@ export function RankingQuestion({
subheader={question.subheader ? getLocalizedValue(question.subheader, languageCode) : ""}
questionId={question.id}
/>
<div className="fb-mt-4">
<div className="mt-4">
<fieldset>
<legend className="fb-sr-only">{t("common.ranking_items")}</legend>
<div className="fb-relative" ref={parent}>
<legend className="sr-only">{t("common.ranking_items")}</legend>
<div className="relative" ref={parent}>
{[...sortedItems, ...unsortedItems].map((item, idx) => {
if (!item) return null;
const isSorted = sortedItems.includes(item);
@@ -184,8 +184,8 @@ export function RankingQuestion({
<div
key={item.id}
className={cn(
"fb-flex fb-h-12 fb-items-center fb-mb-2 fb-border fb-border-border fb-transition-all fb-text-heading hover:fb-bg-input-bg-selected focus-within:fb-border-brand focus-within:fb-shadow-outline focus-within:fb-bg-input-bg-selected fb-rounded-custom fb-relative fb-cursor-pointer w-full focus:outline-none",
isSorted ? "fb-bg-input-bg-selected" : "fb-bg-input-bg"
"border-border text-heading hover:bg-input-bg-selected focus-within:border-brand focus-within:shadow-outline focus-within:bg-input-bg-selected rounded-custom relative mb-2 flex h-12 w-full cursor-pointer items-center border transition-all focus:outline-none",
isSorted ? "bg-input-bg-selected" : "bg-input-bg"
)}>
<button
autoFocus={idx === 0 && autoFocusEnabled}
@@ -204,22 +204,22 @@ export function RankingQuestion({
aria-label={t("common.select_for_ranking", {
item: getLocalizedValue(item.label, languageCode),
})}
className="fb-flex fb-gap-x-4 fb-px-4 fb-items-center fb-grow fb-h-full group text-left focus:outline-none">
className="group flex h-full grow items-center gap-x-4 px-4 text-left focus:outline-none">
<span
className={cn(
"fb-w-6 fb-grow-0 fb-h-6 fb-flex fb-items-center fb-justify-center fb-rounded-full fb-text-xs fb-font-semibold fb-border-brand fb-border",
"border-brand flex h-6 w-6 grow-0 items-center justify-center rounded-full border text-xs font-semibold",
isSorted
? "fb-bg-brand fb-text-white fb-border"
: "fb-border-dashed group-hover:fb-bg-white fb-text-transparent group-hover:fb-text-heading"
? "bg-brand border text-white"
: "group-hover:text-heading border-dashed text-transparent group-hover:bg-white"
)}>
{(idx + 1).toString()}
</span>
<div className="fb-grow fb-shrink fb-font-medium fb-text-sm fb-text-start" dir="auto">
<div className="shrink grow text-start text-sm font-medium" dir="auto">
{getLocalizedValue(item.label, languageCode)}
</div>
</button>
{isSorted ? (
<div className="fb-flex fb-flex-col fb-h-full fb-grow-0 fb-border-l fb-border-border">
<div className="border-border flex h-full grow-0 flex-col border-l">
<button
tabIndex={isFirst ? -1 : 0}
type="button"
@@ -231,10 +231,10 @@ export function RankingQuestion({
item: getLocalizedValue(item.label, languageCode),
})}
className={cn(
"fb-px-2 fb-flex fb-flex-1 fb-items-center fb-justify-center",
"flex flex-1 items-center justify-center px-2",
isFirst
? "fb-opacity-30 fb-cursor-not-allowed"
: "hover:fb-bg-black/5 fb-rounded-tr-custom fb-transition-colors"
? "cursor-not-allowed opacity-30"
: "rounded-tr-custom transition-colors hover:bg-black/5"
)}
disabled={isFirst}>
<svg
@@ -259,10 +259,10 @@ export function RankingQuestion({
handleMove(item.id, "down");
}}
className={cn(
"fb-px-2 fb-flex-1 fb-border-t fb-border-border fb-flex fb-items-center fb-justify-center",
"border-border flex flex-1 items-center justify-center border-t px-2",
isLast
? "fb-opacity-30 fb-cursor-not-allowed"
: "hover:fb-bg-black/5 fb-rounded-br-custom fb-transition-colors"
? "cursor-not-allowed opacity-30"
: "rounded-br-custom transition-colors hover:bg-black/5"
)}
aria-label={t("common.move_down", {
item: getLocalizedValue(item.label, languageCode),
@@ -290,8 +290,8 @@ export function RankingQuestion({
</div>
</fieldset>
</div>
{error ? <div className="fb-text-red-500 fb-mt-2 fb-text-sm">{error}</div> : null}
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
{error ? <div className="mt-2 text-sm text-red-500">{error}</div> : null}
<div className="flex w-full flex-row-reverse justify-between pt-4">
<SubmitButton
tabIndex={isCurrent ? 0 : -1}
buttonLabel={getLocalizedValue(question.buttonLabel, languageCode)}

View File

@@ -85,7 +85,7 @@ export function RatingQuestion({
id={id}
name="rating"
value={number}
className="fb-invisible fb-absolute fb-left-0 fb-h-full fb-w-full fb-cursor-pointer fb-opacity-0"
className="invisible absolute left-0 h-full w-full cursor-pointer opacity-0"
onClick={() => {
handleSelect(number);
}}
@@ -101,17 +101,17 @@ export function RatingQuestion({
const getRatingNumberOptionColor = (range: number, idx: number) => {
if (range > 5) {
if (range - idx < 2) return "fb-bg-emerald-100";
if (range - idx < 4) return "fb-bg-orange-100";
return "fb-bg-rose-100";
if (range - idx < 2) return "bg-emerald-100";
if (range - idx < 4) return "bg-orange-100";
return "bg-rose-100";
} else if (range < 5) {
if (range - idx < 1) return "fb-bg-emerald-100";
if (range - idx < 2) return "fb-bg-orange-100";
return "fb-bg-rose-100";
if (range - idx < 1) return "bg-emerald-100";
if (range - idx < 2) return "bg-orange-100";
return "bg-rose-100";
}
if (range - idx < 2) return "fb-bg-emerald-100";
if (range - idx < 3) return "fb-bg-orange-100";
return "fb-bg-rose-100";
if (range - idx < 2) return "bg-emerald-100";
if (range - idx < 3) return "bg-orange-100";
return "bg-rose-100";
};
return (
@@ -124,7 +124,7 @@ export function RatingQuestion({
setTtc(updatedTtcObj);
onSubmit({ [question.id]: value ?? "" }, updatedTtcObj);
}}
className="fb-w-full">
className="w-full">
{isMediaAvailable ? <QuestionMedia imgUrl={question.imageUrl} videoUrl={question.videoUrl} /> : null}
<Headline
headline={getLocalizedValue(question.headline, languageCode)}
@@ -135,10 +135,10 @@ export function RatingQuestion({
subheader={question.subheader ? getLocalizedValue(question.subheader, languageCode) : ""}
questionId={question.id}
/>
<div className="fb-mb-4 fb-mt-6 fb-flex fb-items-center fb-justify-center">
<fieldset className="fb-w-full">
<legend className="fb-sr-only">Choices</legend>
<div className="fb-flex fb-w-full">
<div className="mb-4 mt-6 flex items-center justify-center">
<fieldset className="w-full">
<legend className="sr-only">Choices</legend>
<div className="flex w-full">
{Array.from({ length: question.range }, (_, i) => i + 1).map((number, i, a) => (
<span
key={number}
@@ -148,7 +148,7 @@ export function RatingQuestion({
onMouseLeave={() => {
setHoveredNumber(0);
}}
className="fb-bg-survey-bg fb-flex-1 fb-text-center fb-text-sm">
className="bg-survey-bg flex-1 text-center text-sm">
{question.scale === "number" ? (
<label
tabIndex={isCurrent ? 0 : -1}
@@ -162,25 +162,25 @@ export function RatingQuestion({
}}
className={cn(
value === number
? "fb-bg-accent-selected-bg fb-border-border-highlight fb-z-10 fb-border"
: "fb-border-border",
? "bg-accent-selected-bg border-border-highlight z-10 border"
: "border-border",
a.length === number
? dir === "rtl"
? "fb-rounded-l-custom fb-border-l"
: "fb-rounded-r-custom fb-border-r"
? "rounded-l-custom border-l"
: "rounded-r-custom border-r"
: "",
number === 1
? dir === "rtl"
? "fb-rounded-r-custom fb-border-r"
: "fb-rounded-l-custom fb-border-l"
? "rounded-r-custom border-r"
: "rounded-l-custom border-l"
: "",
hoveredNumber === number ? "fb-bg-accent-bg" : "",
question.isColorCodingEnabled ? "fb-min-h-[47px]" : "fb-min-h-[41px]",
"fb-text-heading focus:fb-border-brand fb-relative fb-flex fb-w-full fb-cursor-pointer fb-items-center fb-justify-center fb-overflow-hidden fb-border-b fb-border-l fb-border-t focus:fb-border-2 focus:fb-outline-none"
hoveredNumber === number ? "bg-accent-bg" : "",
question.isColorCodingEnabled ? "min-h-[47px]" : "min-h-[41px]",
"text-heading focus:border-brand relative flex w-full cursor-pointer items-center justify-center overflow-hidden border-b border-l border-t focus:border-2 focus:outline-none"
)}>
{question.isColorCodingEnabled ? (
<div
className={`fb-absolute fb-left-0 fb-top-0 fb-h-[6px] fb-w-full ${getRatingNumberOptionColor(question.range, number)}`}
className={`absolute left-0 top-0 h-[6px] w-full ${getRatingNumberOptionColor(question.range, number)}`}
/>
) : null}
<HiddenRadioInput number={number} id={number.toString()} />
@@ -198,11 +198,9 @@ export function RatingQuestion({
}
}}
className={cn(
number <= hoveredNumber || number <= value!
? "fb-text-amber-400"
: "fb-text-[#8696AC]",
hoveredNumber === number ? "fb-text-amber-400" : "",
"fb-relative fb-flex fb-max-h-16 fb-min-h-9 fb-cursor-pointer fb-justify-center focus:fb-outline-none"
number <= hoveredNumber || number <= value! ? "text-amber-400" : "text-[#8696AC]",
hoveredNumber === number ? "text-amber-400" : "",
"relative flex max-h-16 min-h-9 cursor-pointer justify-center focus:outline-none"
)}
onFocus={() => {
setHoveredNumber(number);
@@ -211,7 +209,7 @@ export function RatingQuestion({
setHoveredNumber(0);
}}>
<HiddenRadioInput number={number} id={number.toString()} />
<div className="fb-h-full fb-w-full fb-max-w-[74px] fb-object-contain">
<div className="h-full w-full max-w-[74px] object-contain">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path
fillRule="evenodd"
@@ -224,10 +222,10 @@ export function RatingQuestion({
<label
tabIndex={isCurrent ? 0 : -1}
className={cn(
"fb-relative fb-flex fb-max-h-16 fb-min-h-9 fb-w-full fb-cursor-pointer fb-justify-center",
"relative flex max-h-16 min-h-9 w-full cursor-pointer justify-center",
value === number || hoveredNumber === number
? "fb-stroke-rating-selected fb-text-rating-selected"
: "fb-stroke-heading fb-text-heading focus:fb-border-accent-bg focus:fb-border-2 focus:fb-outline-none"
? "stroke-rating-selected text-rating-selected"
: "stroke-heading text-heading focus:border-accent-bg focus:border-2 focus:outline-none"
)}
onKeyDown={(e) => {
// Accessibility: if spacebar was pressed pass this down to the input
@@ -244,7 +242,7 @@ export function RatingQuestion({
setHoveredNumber(0);
}}>
<HiddenRadioInput number={number} id={number.toString()} />
<div className={cn("fb-h-full fb-w-full fb-max-w-[74px] fb-object-contain")}>
<div className={cn("h-full w-full max-w-[74px] object-contain")}>
<RatingSmiley
active={value === number || hoveredNumber === number}
idx={i}
@@ -257,17 +255,17 @@ export function RatingQuestion({
</span>
))}
</div>
<div className="fb-text-subheading fb-mt-4 fb-flex fb-justify-between fb-px-1.5 fb-text-xs fb-leading-6 fb-gap-8">
<p className="fb-max-w-[50%]" dir="auto">
<div className="text-subheading mt-4 flex justify-between gap-8 px-1.5 text-xs leading-6">
<p className="max-w-[50%]" dir="auto">
{getLocalizedValue(question.lowerLabel, languageCode)}
</p>
<p className="fb-max-w-[50%]" dir="auto">
<p className="max-w-[50%]" dir="auto">
{getLocalizedValue(question.upperLabel, languageCode)}
</p>
</div>
</fieldset>
</div>
<div className="fb-flex fb-flex-row-reverse fb-w-full fb-justify-between fb-pt-4">
<div className="flex w-full flex-row-reverse justify-between pt-4">
{question.required ? (
<div></div>
) : (
@@ -304,37 +302,37 @@ interface RatingSmileyProps {
const getSmileyColor = (range: number, idx: number) => {
if (range > 5) {
if (range - idx < 3) return "fb-fill-emerald-100";
if (range - idx < 5) return "fb-fill-orange-100";
return "fb-fill-rose-100";
if (range - idx < 3) return "fill-emerald-100";
if (range - idx < 5) return "fill-orange-100";
return "fill-rose-100";
} else if (range < 5) {
if (range - idx < 2) return "fb-fill-emerald-100";
if (range - idx < 3) return "fb-fill-orange-100";
return "fb-fill-rose-100";
if (range - idx < 2) return "fill-emerald-100";
if (range - idx < 3) return "fill-orange-100";
return "fill-rose-100";
}
if (range - idx < 3) return "fb-fill-emerald-100";
if (range - idx < 4) return "fb-fill-orange-100";
return "fb-fill-rose-100";
if (range - idx < 3) return "fill-emerald-100";
if (range - idx < 4) return "fill-orange-100";
return "fill-rose-100";
};
const getActiveSmileyColor = (range: number, idx: number) => {
if (range > 5) {
if (range - idx < 3) return "fb-fill-emerald-300";
if (range - idx < 5) return "fb-fill-orange-300";
return "fb-fill-rose-300";
if (range - idx < 3) return "fill-emerald-300";
if (range - idx < 5) return "fill-orange-300";
return "fill-rose-300";
} else if (range < 5) {
if (range - idx < 2) return "fb-fill-emerald-300";
if (range - idx < 3) return "fb-fill-orange-300";
return "fb-fill-rose-300";
if (range - idx < 2) return "fill-emerald-300";
if (range - idx < 3) return "fill-orange-300";
return "fill-rose-300";
}
if (range - idx < 3) return "fb-fill-emerald-300";
if (range - idx < 4) return "fb-fill-orange-300";
return "fb-fill-rose-300";
if (range - idx < 3) return "fill-emerald-300";
if (range - idx < 4) return "fill-orange-300";
return "fill-rose-300";
};
const getSmiley = (iconIdx: number, idx: number, range: number, active: boolean, addColors: boolean) => {
const activeColor = addColors ? getActiveSmileyColor(range, idx) : "fb-fill-rating-fill";
const inactiveColor = addColors ? getSmileyColor(range, idx) : "fb-fill-none";
const activeColor = addColors ? getActiveSmileyColor(range, idx) : "fill-rating-fill";
const inactiveColor = addColors ? getSmileyColor(range, idx) : "fill-none";
const icons = [
<TiredFace key="tired-face" className={active ? activeColor : inactiveColor} />,

View File

@@ -63,11 +63,11 @@ export function AutoCloseWrapper({
}, [survey.autoClose]);
return (
<div className="fb-h-full fb-w-full fb-flex fb-flex-col">
<div className="flex h-full w-full flex-col">
<div // NOSONAR // We can't have a role="button" here as sonarqube registers more issues with this. This is indeed an interactive element.
onClick={stopCountdown}
onMouseOver={stopCountdown} // NOSONAR // We can't check for onFocus because the survey is auto focused after the first question and we don't want to stop the countdown
className="fb-h-full fb-w-full"
className="h-full w-full"
data-testid="fb__surveys__auto-close-wrapper-test"
onKeyDown={stopCountdown}
aria-label={t("common.auto_close_wrapper")}
@@ -75,7 +75,7 @@ export function AutoCloseWrapper({
{children}
</div>
{survey.type === "app" && survey.autoClose && (
<div className="fb-h-2 fb-w-full" aria-hidden={!showAutoCloseProgressBar}>
<div className="h-2 w-full" aria-hidden={!showAutoCloseProgressBar}>
{showAutoCloseProgressBar && <AutoCloseProgressBar autoCloseTimeout={survey.autoClose} />}
</div>
)}

View File

@@ -73,28 +73,28 @@ export const ScrollableContainer = forwardRef<ScrollableContainerHandle, Scrolla
}
return (
<div className="fb-relative">
<div className="relative">
{!isAtTop && (
<div className="fb-from-survey-bg fb-absolute fb-left-0 fb-right-2 fb-top-0 fb-z-10 fb-h-4 fb-bg-gradient-to-b fb-to-transparent" />
<div className="from-survey-bg absolute left-0 right-2 top-0 z-10 h-4 bg-gradient-to-b to-transparent" />
)}
<div
ref={containerRef}
style={{
maxHeight,
}}
className={cn("fb-overflow-auto fb-px-4 fb-bg-survey-bg")}>
className={cn("bg-survey-bg overflow-auto px-4")}>
{children}
</div>
{!isAtBottom && (
<>
<div className="fb-from-survey-bg fb-absolute fb-bottom-0 fb-left-4 fb-right-4 fb-h-4 fb-bg-gradient-to-t fb-to-transparent" />
<div className="from-survey-bg absolute bottom-0 left-4 right-4 h-4 bg-gradient-to-t to-transparent" />
<button
type="button"
onClick={scrollToBottom}
style={{ transform: "translateX(-50%)" }}
className="fb-absolute fb-bottom-2 fb-left-1/2 fb-z-20 fb-flex fb-h-8 fb-w-8 fb-items-center fb-justify-center fb-rounded-full fb-bg-survey-bg fb-border fb-border-transparent hover:fb-border-border fb-shadow-lg fb-transition-colors focus:fb-ring-2 focus:fb-outline-none focus:fb-ring-brand focus:fb-ring-offset-2"
className="bg-survey-bg hover:border-border focus:ring-brand absolute bottom-2 left-1/2 z-20 flex h-8 w-8 items-center justify-center rounded-full border border-transparent shadow-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2"
aria-label="Scroll to bottom">
<ChevronDownIcon className="fb-text-heading fb-w-5 fb-h-5" />
<ChevronDownIcon className="text-heading h-5 w-5" />
</button>
</>
)}

View File

@@ -45,7 +45,7 @@ export const StackedCard = ({
};
const getDummyCardContent = () => {
return <div style={{ height: cardHeight }} className="fb-w-full fb-p-6"></div>;
return <div style={{ height: cardHeight }} className="w-full p-6"></div>;
};
const calculateCardTransform = useMemo(() => {
@@ -111,7 +111,7 @@ export const StackedCard = ({
...straightCardArrangementStyles,
...getBottomStyles(),
}}
className="fb-pointer fb-rounded-custom fb-bg-survey-bg fb-absolute fb-inset-x-0 fb-transition-all fb-ease-in-out fb-overflow-hidden">
className="pointer rounded-custom bg-survey-bg absolute inset-x-0 overflow-hidden transition-all ease-in-out">
<div
style={{
opacity: contentOpacity,

View File

@@ -85,7 +85,7 @@ export function StackedCardsContainer({
const borderStyles = useMemo(() => {
const baseStyle = {
border: "1px solid",
borderRadius: "var(--fb-border-radius)",
borderRadius: "var(--border-radius)",
};
// Determine borderColor based on the survey type and availability of highlightBorderColor
const borderColor =
@@ -142,7 +142,7 @@ export function StackedCardsContainer({
return (
<div
data-testid="stacked-cards-container"
className="fb-relative fb-flex fb-h-full fb-items-end fb-justify-center md:fb-items-center"
className="relative flex h-full items-end justify-center md:items-center"
onMouseEnter={() => {
setHovered(true);
}}
@@ -154,7 +154,7 @@ export function StackedCardsContainer({
<div
id={`questionCard-${questionIdxTemp.toString()}`}
data-testid={`questionCard-${questionIdxTemp.toString()}`}
className={cn("fb-w-full fb-bg-survey-bg fb-overflow-hidden", fullSizeCards ? "fb-h-full" : "")}
className={cn("bg-survey-bg w-full overflow-hidden", fullSizeCards ? "h-full" : "")}
style={borderStyles}>
{getCardContent(questionIdxTemp, 0)}
</div>

View File

@@ -51,17 +51,17 @@ export function SurveyContainer({
const getPlacementStyle = (placement: TPlacement): string => {
switch (placement) {
case "bottomRight":
return "sm:fb-bottom-3 sm:fb-right-3";
return "sm:bottom-3 sm:right-3";
case "topRight":
return "sm:fb-top-3 sm:fb-right-3 sm:fb-bottom-3";
return "sm:top-3 sm:right-3 sm:bottom-3";
case "topLeft":
return "sm:fb-top-3 sm:fb-left-3 sm:fb-bottom-3";
return "sm:top-3 sm:left-3 sm:bottom-3";
case "bottomLeft":
return "sm:fb-bottom-3 sm:fb-left-3";
return "sm:bottom-3 sm:left-3";
case "center":
return "sm:fb-top-1/2 sm:fb-left-1/2 sm:fb-transform sm:-fb-translate-x-1/2 sm:-fb-translate-y-1/2";
return "sm:top-1/2 sm:left-1/2 sm:transform sm:-translate-x-1/2 sm:-translate-y-1/2";
default:
return "sm:fb-bottom-3 sm:fb-right-3";
return "sm:bottom-3 sm:right-3";
}
};
@@ -69,33 +69,33 @@ export function SurveyContainer({
if (!isModal) {
return (
<div id="fbjs" className="fb-formbricks-form" style={{ height: "100%", width: "100%" }} dir={dir}>
<div id="fbjs" className="formbricks-form" style={{ height: "100%", width: "100%" }} dir={dir}>
{children}
</div>
);
}
return (
<div id="fbjs" className="fb-formbricks-form" dir={dir}>
<div id="fbjs" className="formbricks-form" dir={dir}>
<div
aria-live="assertive"
className={cn(
isCenter ? "fb-pointer-events-auto" : "fb-pointer-events-none",
isModal && "fb-z-999999 fb-fixed fb-inset-0 fb-flex fb-items-end"
isCenter ? "pointer-events-auto" : "pointer-events-none",
isModal && "z-999999 fixed inset-0 flex items-end"
)}>
<div
className={cn(
"fb-relative fb-h-full fb-w-full",
!isCenter ? "fb-bg-none fb-transition-all fb-duration-500 fb-ease-in-out" : "",
isModal && isCenter && darkOverlay ? "fb-bg-slate-700/80" : "",
isModal && isCenter && !darkOverlay ? "fb-bg-white/50" : ""
"relative h-full w-full",
!isCenter ? "bg-none transition-all duration-500 ease-in-out" : "",
isModal && isCenter && darkOverlay ? "bg-slate-700/80" : "",
isModal && isCenter && !darkOverlay ? "bg-white/50" : ""
)}>
<div
ref={modalRef}
className={cn(
getPlacementStyle(placement),
isOpen ? "fb-opacity-100" : "fb-opacity-0",
"fb-rounded-custom fb-pointer-events-auto fb-absolute fb-bottom-0 fb-h-fit fb-w-full fb-overflow-visible fb-bg-white fb-shadow-lg fb-transition-all fb-duration-500 fb-ease-in-out sm:fb-m-4 sm:fb-max-w-sm"
isOpen ? "opacity-100" : "opacity-0",
"rounded-custom pointer-events-auto absolute bottom-0 h-fit w-full overflow-visible bg-white shadow-lg transition-all duration-500 ease-in-out sm:m-4 sm:max-w-sm"
)}>
<div>{children}</div>
</div>

View File

@@ -274,10 +274,10 @@ describe("addCustomThemeToDom", () => {
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
const variables = getCssVariables(styleElement);
expect(variables["--fb-brand-color"]).toBe("#0000FF");
expect(variables["--fb-focus-color"]).toBe("#0000FF");
expect(variables["--fb-brand-text-color"]).toBe("white"); // isLight('#0000FF') is false
expect(variables["--fb-border-radius"]).toBe("8px"); // Default roundness
expect(variables["--brand-color"]).toBe("#0000FF");
expect(variables["--focus-color"]).toBe("#0000FF");
expect(variables["--brand-text-color"]).toBe("white"); // isLight('#0000FF') is false
expect(variables["--border-radius"]).toBe("8px"); // Default roundness
});
test("should apply brand-text-color as black for light brandColor", () => {
@@ -285,7 +285,7 @@ describe("addCustomThemeToDom", () => {
addCustomThemeToDom({ styling });
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
const variables = getCssVariables(styleElement);
expect(variables["--fb-brand-text-color"]).toBe("black"); // isLight('#FFFF00') is true
expect(variables["--brand-text-color"]).toBe("black"); // isLight('#FFFF00') is true
});
test("should default brand-text-color to white if brandColor is undefined", () => {
@@ -293,7 +293,7 @@ describe("addCustomThemeToDom", () => {
addCustomThemeToDom({ styling });
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
const variables = getCssVariables(styleElement);
expect(variables["--fb-brand-text-color"]).toBe("#ffffff");
expect(variables["--brand-text-color"]).toBe("#ffffff");
});
test("should apply all survey styling properties", () => {
@@ -315,25 +315,25 @@ describe("addCustomThemeToDom", () => {
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
const variables = getCssVariables(styleElement);
expect(variables["--fb-brand-color"]).toBe("#112233");
expect(variables["--fb-focus-color"]).toBe("#112233");
expect(variables["--fb-brand-text-color"]).toBe("white");
expect(variables["--fb-heading-color"]).toBe("#AABBCC");
expect(variables["--fb-subheading-color"]).toBe("#AABBCC");
expect(variables["--fb-placeholder-color"]).toBeDefined(); // Relies on mixColor
expect(variables["--fb-border-color"]).toBe("#DDDDDD");
expect(variables["--fb-border-color-highlight"]).toBeDefined(); // Relies on mixColor
expect(variables["--fb-survey-background-color"]).toBe("#EEEEEE");
expect(variables["--fb-survey-border-color"]).toBe("#CCCCCC");
expect(variables["--fb-border-radius"]).toBe("12px");
expect(variables["--fb-input-background-color"]).toBe("#F0F0F0");
expect(variables["--fb-signature-text-color"]).toBeDefined(); // Relies on mixColor & isLight
expect(variables["--fb-branding-text-color"]).toBeDefined(); // Relies on mixColor & isLight
expect(variables["--fb-input-background-color-selected"]).toBeDefined(); // Relies on mixColor
expect(variables["--fb-accent-background-color"]).toBeDefined(); // Relies on mixColor
expect(variables["--fb-accent-background-color-selected"]).toBeDefined(); // Relies on mixColor
expect(variables["--brand-color"]).toBe("#112233");
expect(variables["--focus-color"]).toBe("#112233");
expect(variables["--brand-text-color"]).toBe("white");
expect(variables["--heading-color"]).toBe("#AABBCC");
expect(variables["--subheading-color"]).toBe("#AABBCC");
expect(variables["--placeholder-color"]).toBeDefined(); // Relies on mixColor
expect(variables["--border-color"]).toBe("#DDDDDD");
expect(variables["--border-color-highlight"]).toBeDefined(); // Relies on mixColor
expect(variables["--survey-background-color"]).toBe("#EEEEEE");
expect(variables["--survey-border-color"]).toBe("#CCCCCC");
expect(variables["--border-radius"]).toBe("12px");
expect(variables["--input-background-color"]).toBe("#F0F0F0");
expect(variables["--signature-text-color"]).toBeDefined(); // Relies on mixColor & isLight
expect(variables["--branding-text-color"]).toBeDefined(); // Relies on mixColor & isLight
expect(variables["--input-background-color-selected"]).toBeDefined(); // Relies on mixColor
expect(variables["--accent-background-color"]).toBeDefined(); // Relies on mixColor
expect(variables["--accent-background-color-selected"]).toBeDefined(); // Relies on mixColor
// calendar-tile-color depends on isLight(brandColor)
expect(variables["--fb-calendar-tile-color"]).toBeUndefined(); // isLight('#112233') is false, so this should be undefined
expect(variables["--calendar-tile-color"]).toBeUndefined(); // isLight('#112233') is false, so this should be undefined
});
test("should set signature and branding text colors for dark questionColor", () => {
@@ -346,8 +346,8 @@ describe("addCustomThemeToDom", () => {
const variables = getCssVariables(styleElement);
// For dark questionColor ('#202020'), isLight is false, so mix with white.
expect(variables["--fb-signature-text-color"]).toBeDefined();
expect(variables["--fb-branding-text-color"]).toBeDefined();
expect(variables["--signature-text-color"]).toBeDefined();
expect(variables["--branding-text-color"]).toBeDefined();
});
test("should handle roundness 0 correctly", () => {
@@ -355,7 +355,7 @@ describe("addCustomThemeToDom", () => {
addCustomThemeToDom({ styling });
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
const variables = getCssVariables(styleElement);
expect(variables["--fb-border-radius"]).toBe("0px");
expect(variables["--border-radius"]).toBe("0px");
});
test("should set input-background-color-selected to slate-50 for white inputColor", () => {
@@ -365,7 +365,7 @@ describe("addCustomThemeToDom", () => {
addCustomThemeToDom({ styling });
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
const variables = getCssVariables(styleElement);
expect(variables["--fb-input-background-color-selected"]).toBe("var(--slate-50)");
expect(variables["--input-background-color-selected"]).toBe("var(--slate-50)");
});
});
@@ -379,8 +379,8 @@ describe("addCustomThemeToDom", () => {
const variables = getCssVariables(styleElement);
// We can't easily test the exact mixed color without duplicating mixColor logic or having access to its exact output for these inputs.
// So, we just check that it's defined and not the slate-50 default.
expect(variables["--fb-input-background-color-selected"]).toBeDefined();
expect(variables["--fb-input-background-color-selected"]).not.toBe("var(--slate-50)");
expect(variables["--input-background-color-selected"]).toBeDefined();
expect(variables["--input-background-color-selected"]).not.toBe("var(--slate-50)");
});
test("should not set calendar-tile-color if brandColor is undefined", () => {
@@ -388,7 +388,7 @@ describe("addCustomThemeToDom", () => {
addCustomThemeToDom({ styling });
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
const variables = getCssVariables(styleElement);
expect(variables["--fb-calendar-tile-color"]).toBeUndefined();
expect(variables["--calendar-tile-color"]).toBeUndefined();
});
test("should not define variables for undefined styling properties", () => {
@@ -397,11 +397,11 @@ describe("addCustomThemeToDom", () => {
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
const variables = getCssVariables(styleElement);
expect(variables["--fb-brand-color"]).toBe("#ABC");
expect(variables["--brand-color"]).toBe("#ABC");
// Check a few that would not be set
expect(variables["--fb-heading-color"]).toBeUndefined();
expect(variables["--fb-survey-background-color"]).toBeUndefined();
expect(variables["--fb-input-background-color"]).toBeUndefined();
expect(variables["--heading-color"]).toBeUndefined();
expect(variables["--survey-background-color"]).toBeUndefined();
expect(variables["--input-background-color"]).toBeUndefined();
});
test("should apply nonce to new custom theme style element when nonce is set", () => {

View File

@@ -85,7 +85,7 @@ export const addCustomThemeToDom = ({ styling }: { styling: TProjectStyling | TS
// Helper function to append the variable if it's not undefined
const appendCssVariable = (variableName: string, value?: string) => {
if (value !== undefined) {
cssVariables += `--fb-${variableName}: ${value};\n`;
cssVariables += `--${variableName}: ${value};\n`;
}
};

View File

@@ -6,7 +6,7 @@
height: 160px;
display: flex;
background: rgb(248 250 252);
background: var(--fb-survey-background-color);
background: var(--survey-background-color);
flex-direction: row-reverse;
gap: 8px;
justify-content: center;
@@ -56,7 +56,7 @@
.calendar-root {
position: absolute !important;
top: 0 !important;
background: var(--fb-survey-background-color) !important;
background: var(--survey-background-color) !important;
width: 100% !important;
}
@@ -85,7 +85,7 @@
}
.react-calendar__month-view__weekdays__weekday {
color: var(--fb-heading-color);
color: var(--heading-color);
font-weight: 400;
text-transform: capitalize;
}
@@ -100,7 +100,7 @@
}
.react-calendar__tile--active {
background: var(--fb-brand-color) !important;
background: var(--brand-color) !important;
border-radius: 6px;
}

View File

@@ -19,7 +19,7 @@
}
#fbjs *::-webkit-scrollbar-thumb {
background-color: var(--fb-brand-color);
background-color: var(--brand-color);
border: none;
border-radius: 10px;
}
@@ -27,18 +27,18 @@
/* Firefox */
#fbjs * {
scrollbar-width: thin;
scrollbar-color: var(--fb-brand-color) transparent;
scrollbar-color: var(--brand-color) transparent;
}
/* this is for styling the HtmlBody component */
.fb-htmlbody {
@apply fb-block fb-text-sm fb-font-normal fb-leading-6;
.htmlbody {
@apply block text-sm font-normal leading-6;
/* need to use !important because in packages/ui/components/editor/styles-editor-frontend.css the color is defined for some classes */
color: var(--fb-subheading-color) !important;
color: var(--subheading-color) !important;
}
/* without this, it wont override the color */
p.fb-editor-paragraph {
p.editor-paragraph {
overflow-wrap: break-word;
}
@@ -62,33 +62,33 @@ p.fb-editor-paragraph {
--yellow-500: rgb(234 179 8);
/* Default Light Theme, you can override everything by changing these values */
--fb-brand-color: var(--brand-default);
--fb-brand-text-color: black;
--fb-border-color: var(--slate-300);
--fb-border-color-highlight: var(--slate-500);
--fb-focus-color: var(--slate-500);
--fb-heading-color: var(--slate-900);
--fb-subheading-color: var(--slate-700);
--fb-placeholder-color: var(--slate-300);
--fb-info-text-color: var(--slate-500);
--fb-signature-text-color: var(--slate-500);
--fb-branding-text-color: var(--slate-500);
--fb-survey-background-color: white;
--fb-survey-border-color: var(--slate-50);
--fb-accent-background-color: var(--slate-200);
--fb-accent-background-color-selected: var(--slate-100);
--fb-input-background-color: var(--slate-50);
--fb-input-background-color-selected: var(--slate-200);
--fb-placeholder-color: var(--slate-400);
--fb-rating-fill: var(--yellow-100);
--fb-rating-hover: var(--yellow-500);
--fb-back-btn-border: transparent;
--fb-submit-btn-border: transparent;
--fb-rating-selected: black;
--fb-close-btn-color: var(--slate-500);
--fb-close-btn-color-hover: var(--slate-700);
--fb-calendar-tile-color: var(--slate-50);
--fb-border-radius: 8px;
--brand-color: var(--brand-default);
--brand-text-color: black;
--border-color: var(--slate-300);
--border-color-highlight: var(--slate-500);
--focus-color: var(--slate-500);
--heading-color: var(--slate-900);
--subheading-color: var(--slate-700);
--placeholder-color: var(--slate-300);
--info-text-color: var(--slate-500);
--signature-text-color: var(--slate-500);
--branding-text-color: var(--slate-500);
--survey-background-color: white;
--survey-border-color: var(--slate-50);
--accent-background-color: var(--slate-200);
--accent-background-color-selected: var(--slate-100);
--input-background-color: var(--slate-50);
--input-background-color-selected: var(--slate-200);
--placeholder-color: var(--slate-400);
--rating-fill: var(--yellow-100);
--rating-hover: var(--yellow-500);
--back-btn-border: transparent;
--submit-btn-border: transparent;
--rating-selected: black;
--close-btn-color: var(--slate-500);
--close-btn-color-hover: var(--slate-700);
--calendar-tile-color: var(--slate-50);
--border-radius: 8px;
}
@keyframes shrink-width-to-zero {
@@ -101,7 +101,7 @@ p.fb-editor-paragraph {
}
}
.fb-no-scrollbar {
.no-scrollbar {
-ms-overflow-style: none !important;
/* Internet Explorer 10+ */
scrollbar-width: thin !important;

View File

@@ -1,7 +1,6 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
important: "#fbjs",
prefix: "fb-",
darkMode: "class",
corePlugins: {
preflight: false,
@@ -10,35 +9,34 @@ module.exports = {
theme: {
extend: {
colors: {
brand: "var(--fb-brand-color)",
"on-brand": "var(--fb-brand-text-color)",
border: "var(--fb-border-color)",
"border-highlight": "var(--fb-border-color-highlight)",
focus: "var(--fb-focus-color)",
heading: "var(--fb-heading-color)",
subheading: "var(--fb-subheading-color)",
placeholder: "var(--fb-placeholder-color)",
"info-text": "var(--fb-info-text-color)",
signature: "var(--fb-signature-text-color)",
"branding-text": "var(--fb-branding-text-color)",
"survey-bg": "var(--fb-survey-background-color)",
"survey-border": "var(--fb-survey-border-color)",
"accent-bg": "var(--fb-accent-background-color)",
"accent-selected-bg": "var(--fb-accent-background-color-selected)",
"input-bg": "var(--fb-input-background-color)",
"input-bg-selected": "var(--fb-input-background-color-selected)",
placeholder: "var(--fb-placeholder-color)",
"rating-fill": "var(--fb-rating-fill)",
"rating-focus": "var(--fb-rating-hover)",
"rating-selected": "var(--fb-rating-selected)",
"back-button-border": "var(--fb-back-btn-border)",
"submit-button-border": "var(--fb-submit-btn-border)",
"close-button": "var(--fb-close-btn-color)",
"close-button-focus": "var(--fb-close-btn-hover-color)",
"calendar-tile": "var(--fb-calendar-tile-color)",
brand: "var(--brand-color)",
"on-brand": "var(--brand-text-color)",
border: "var(--border-color)",
"border-highlight": "var(--border-color-highlight)",
focus: "var(--focus-color)",
heading: "var(--heading-color)",
subheading: "var(--subheading-color)",
placeholder: "var(--placeholder-color)",
"info-text": "var(--info-text-color)",
signature: "var(--signature-text-color)",
"branding-text": "var(--branding-text-color)",
"survey-bg": "var(--survey-background-color)",
"survey-border": "var(--survey-border-color)",
"accent-bg": "var(--accent-background-color)",
"accent-selected-bg": "var(--accent-background-color-selected)",
"input-bg": "var(--input-background-color)",
"input-bg-selected": "var(--input-background-color-selected)",
"rating-fill": "var(--rating-fill)",
"rating-focus": "var(--rating-hover)",
"rating-selected": "var(--rating-selected)",
"back-button-border": "var(--back-btn-border)",
"submit-button-border": "var(--submit-btn-border)",
"close-button": "var(--close-btn-color)",
"close-button-focus": "var(--close-btn-color-hover)",
"calendar-tile": "var(--calendar-tile-color)",
},
borderRadius: {
custom: "var(--fb-border-radius)",
custom: "var(--border-radius)",
},
zIndex: {
999999: "999999",