<!-- source-hash: e6e63274e2215026ef420402aa7a9e8f -->
A self-contained, reusable contact form component that supports both standard contact submission and custom ticket-creation flows via configurable props. It handles field visibility toggling, attachment staging, Zod validation, and dual submit paths (built-in API vs. caller-provided handler).

## Key Components

**Exported Types**
- `ContactFormHideableField` — Union type of the six fields that can be suppressed from the UI (`name`, `email`, `companySize`, `referralSource`, `helpCategory`, `message`)
- `ContactFormProps` — Full prop interface covering attribution, pre-fill, layout, submission, and slot customization

**Main Export**
- `ContactForm` — The primary form component

**Internal Hooks Used**
- `useForm` (react-hook-form) + `zodResolver` against `ContactSchema`
- `useContactSubmission` — built-in `/api/contact` submit path with toast + redirect
- `useChatAttachments` — file staging shared with the chat composer
- `useState` — tracks in-flight state for the custom submit path

## Usage Example

```typescript
// Standard contact page — built-in submit flow
<ContactForm
  userId={user?.id}
  helpCategoryOptions={appConfig.contact.contactReasons}
  rdtCid={getStoredRedditClickId()}
  onSubmitSuccess={clearStoredRedditClickId}
/>

// Ticket creation — custom submit, hidden fields, extra Subject input
<ContactForm
  hideFields={['name', 'email', 'companySize', 'referralSource', 'helpCategory']}
  defaultValues={{ name: user.name, email: user.email, helpCategory: 'Support' }}
  attachmentsEnabled
  extraTopField={<SubjectInput value={subject} onChange={setSubject} />}
  submitLabel="Open ticket"
  onCustomSubmit={async (data, attachments) => {
    await actions.submitTicket({ ...data, subject, attachments })
  }}
/>
```

> **Note:** When hiding `name`, `email`, or `helpCategory`, you **must** supply their values via `defaultValues` — Zod still validates them even when the fields are not rendered. Hidden `<input type="hidden">` elements ensure react-hook-form includes them in the submit payload.