144 lines · 5.7 KB
import { optionLabel } from "~/lib/issue-templates";
import type { IssueFormField } from "~/lib/issue-templates";
import { Select as KumoSelect } from "@cloudflare/kumo/components/select";
import { Markdown } from "~/ui/Markdown";
import { inputClass } from "~/ui/Field";
import { cn } from "~/utils/cn";

type Answers = Record<string, string | string[]>;
type Props = { fields: IssueFormField[]; answers: Answers; onChange: (answers: Answers) => void; markdown: string[] };

function Label({ htmlFor, text, required }: { htmlFor: string; text: string; required: boolean }) {
  return (
    <label htmlFor={htmlFor} className="block text-sm font-medium text-kumo-default">
      {text}
      {required && <span className="ml-1 text-kumo-danger">*</span>}
    </label>
  );
}

/** Renders a `.gitfor/ISSUE_TEMPLATE` issue form; `markdown` holds server-rendered HTML for markdown blocks. */
export function IssueForm({ fields, answers, onChange, markdown }: Props) {
  const set = (key: string, value: string | string[]) => onChange({ ...answers, [key]: value });
  let markdownIndex = 0;
  return (
    <div className="space-y-5">
      {fields.map((field, index) => {
        if (field.type === "markdown") {
          const html = markdown[markdownIndex++] ?? "";
          return <Markdown key={`md:${html}`} html={html} className="text-sm" />;
        }
        const key = field.id ?? `field-${index}`;
        const id = `issue-form-${key}`;
        const description = field.attributes.description && (
          <p className="text-xs text-kumo-subtle">{field.attributes.description}</p>
        );
        if (field.type === "checkboxes") {
          const checked = new Set(Array.isArray(answers[key]) ? answers[key] : []);
          return (
            <fieldset key={key} className="space-y-1.5">
              <legend className="text-sm font-medium text-kumo-default">{field.attributes.label}</legend>