Skip to content

Commit

Permalink
Add "description" disclosure element to Matrix form fields
Browse files Browse the repository at this point in the history
  • Loading branch information
underbluewaters committed Sep 30, 2024
1 parent b820274 commit f977f36
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 10 deletions.
40 changes: 34 additions & 6 deletions packages/client/src/formElements/FormElementOptionsInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { FormLanguageContext, SurveyContext } from "./FormElement";
export type FormElementOption = {
value?: string;
label: string;
description?: string;
};

export default function FormElementOptionsInput({
Expand All @@ -17,13 +18,15 @@ export default function FormElementOptionsInput({
onChange,
heading,
description,
promptForDescription,
}: {
prop: string;
componentSettings?: { [key: string]: any };
alternateLanguageSettings?: { [lang: string]: { [key: string]: any } };
onChange: (options: FormElementOption[]) => void;
heading?: string;
description?: ReactNode | string;
promptForDescription?: boolean;
}) {
const context = useContext(FormLanguageContext);
const { t } = useTranslation("admin:surveys");
Expand Down Expand Up @@ -91,7 +94,7 @@ export default function FormElementOptionsInput({
<Trans ns="admin:surveys">
List options as{" "}
<code className="font-mono bg-gray-100 p-1 rounded">
label,value{" "}
label,value{promptForDescription ? ",description" : ""}{" "}
</code>
each on a new line. Use quotes to escape commas. Values are not
required but will keep data consistent if text changes are needed.
Expand Down Expand Up @@ -154,16 +157,32 @@ export default function FormElementOptionsInput({
function toText(options: FormElementOption[]): string {
return Papa.unparse(
options.map((option) =>
option.value ? [option.label, option.value] : [option.label]
)
);
option.value
? option.description
? [
option.label,
option.value,
`${option.description.replace(/^"/, "").replace(/"$/, "")}`,
]
: [option.label, option.value]
: [option.label]
),
{
// using the Mongolian vowel separator as a quote character, as it
// is unlikely to be used in user-generated content
quoteChar: "\u180E",
}
).replace(/\u180E/g, "");
}

function fromText(text: string) {
let options: FormElementOption[] = [];
let errors: string[] = [];
let delimiter: string | undefined = undefined;
const result = Papa.parse(text, { skipEmptyLines: true });
// eslint-disable-next-line i18next/no-literal-string
const result = Papa.parse(text, {
skipEmptyLines: true,
});
if (
result.errors?.length &&
result.errors.filter((e) => e.type !== "Delimiter").length
Expand All @@ -173,7 +192,16 @@ function fromText(text: string) {
options = result.data.map((r: any) =>
r.length === 1
? { label: r[0].trim() }
: { label: r[0].trim(), value: r[1].trim() }
: {
label: r[0].trim(),
value: r[1].trim(),
description: r
.slice(2)
?.join(",")
.trim()
.replace(/^"/, "")
.replace(/"$/, ""),
}
);
if (options.length === 0) {
errors = ["No options specified"];
Expand Down
24 changes: 20 additions & 4 deletions packages/client/src/formElements/Matrix.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { TableIcon } from "@heroicons/react/outline";
import React, { useContext } from "react";
import { Trans, useTranslation } from "react-i18next";
import { Trans } from "react-i18next";
import { SurveyStyleContext } from "../surveys/appearance";
import {
FormElementBody,
FormElementComponent,
FormElementEditorPortal,
FormLanguageContext,
SurveyContext,
useLocalizedComponentSetting,
} from "./FormElement";
import FormElementOptionsInput, {
FormElementOption,
} from "./FormElementOptionsInput";
import { questionBodyFromMarkdown } from "./fromMarkdown";
import { InfoCircledIcon } from "@radix-ui/react-icons";
import useDialog from "../components/useDialog";

export type MatrixProps = {
options?: FormElementOption[];
Expand All @@ -36,6 +37,8 @@ const Matrix: FormElementComponent<MatrixProps, MatrixValue> = (props) => {
props
) as FormElementOption[];

const { alert } = useDialog();

function updateValue(row: FormElementOption, option: string) {
const newValue = { ...props.value, [row.value || row.label]: option };
if (option === "") {
Expand Down Expand Up @@ -89,6 +92,18 @@ const Matrix: FormElementComponent<MatrixProps, MatrixValue> = (props) => {
<React.Fragment key={row.label}>
<div className="px-2 items-center flex bg-black bg-opacity-10 ltr:rounded-l rtl:rounded-r">
{row.label}
{row.description && row.description.length > 0 && (
<button
className="ml-1.5"
onClick={() => {
alert(row.label, {
description: row.description,
});
}}
>
<InfoCircledIcon />
</button>
)}
</div>
<div
className={`flex w-32 sm:w-auto items-center bg-black bg-opacity-10 p-2 ltr:rounded-r rtl:rounded-l`}
Expand Down Expand Up @@ -149,8 +164,9 @@ const Matrix: FormElementComponent<MatrixProps, MatrixValue> = (props) => {
return (
<>
<FormElementOptionsInput
promptForDescription
heading="Rows"
key={props.id}
key={props.id + "rows"}
prop="rows"
componentSettings={props.componentSettings}
alternateLanguageSettings={props.alternateLanguageSettings}
Expand All @@ -162,7 +178,7 @@ const Matrix: FormElementComponent<MatrixProps, MatrixValue> = (props) => {
)}
/>
<FormElementOptionsInput
key={props.id}
key={props.id + "options"}
prop="options"
componentSettings={props.componentSettings}
alternateLanguageSettings={props.alternateLanguageSettings}
Expand Down

0 comments on commit f977f36

Please sign in to comment.