Skip to content

fix: pass useUpload hook at F0Form level instead of field-level#3752

Open
sauldom102 wants to merge 1 commit intomainfrom
fix-pass-use-upload-at-f0form-level
Open

fix: pass useUpload hook at F0Form level instead of field-level#3752
sauldom102 wants to merge 1 commit intomainfrom
fix-pass-use-upload-at-f0form-level

Conversation

@sauldom102
Copy link
Copy Markdown
Collaborator

Move useUpload from file field config to F0Form level

What

Lifts the useUpload hook from individual file field configurations (f0FormField) to a form-level prop on <F0Form>. All file fields in a form now share the same upload hook provided once at the form level.

Why

Previously, every file field required its own useUpload in the field config, leading to repetitive boilerplate. Since all file fields in a form typically use the same upload mechanism, it makes more sense to declare it once at the form level.

Changes

  • fields/file/types.ts — Removed useUpload from F0FileConfig and F0FileField
  • types.ts — Added useUpload?: UseFileUpload to all 4 form prop interfaces (F0FormPropsWithSingleSchema, F0FormPropsWithPerSectionSchema, F0FormPropsWithSingleSchemaDefinition, F0FormPropsWithPerSectionDefinition)
  • context.ts — Added useUpload to F0FormContextValue so file fields can access it via context
  • F0Form.tsx — Threads useUpload through all code paths (single schema, per-section, definition adapters) into the form context
  • F0FormSection.tsx — Accepts and forwards useUpload into section-level context
  • FileFieldRenderer.tsx — Resolves useUpload from context instead of field.useUpload
  • f0Schema.ts — Removed useUpload-based file field type inference (file fields must use fieldType: "file" explicitly)
  • useSchemaDefinition.ts — Removed useUpload mapping in the file field case
  • Stories & tests — Updated to pass useUpload at the <F0Form> level

Usage

// Before
f0FormField(z.string(), {
  fieldType: "file",
  useUpload: useMyUpload,
})

// After
f0FormField(z.string(), { fieldType: "file" })

<F0Form
  formDefinition={formDefinition}
  useUpload={useMyUpload}
/>

@sauldom102 sauldom102 requested a review from a team as a code owner March 24, 2026 17:00
Copilot AI review requested due to automatic review settings March 24, 2026 17:00
@github-actions github-actions bot added fix react Changes affect packages/react labels Mar 24, 2026
@github-actions
Copy link
Copy Markdown
Contributor

✅ No New Circular Dependencies

No new circular dependencies detected. Current count: 0

@github-actions
Copy link
Copy Markdown
Contributor

📦 Alpha Package Version Published

Use pnpm i github:factorialco/f0#npm/alpha-pr-3752 to install the package

Use pnpm i github:factorialco/f0#f930612c3eedc444dc8ac21d3e63136391e04ffe to install this specific commit

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Visual review for your branch is published 🔍

Here are the links to:

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors F0Form’s file upload configuration by moving useUpload from per-field config to a single, form-level prop that is exposed to file fields through F0FormContext.

Changes:

  • Adds useUpload?: UseFileUpload to F0Form props and threads it into F0FormContext (single schema, per-section, and definition adapters).
  • Removes useUpload from file field config/runtime field types and removes useUpload-based file type inference.
  • Updates file field rendering/tests/stories to source upload behavior from the form-level useUpload.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/react/src/components/F0Form/useSchemaDefinition.ts Stops mapping useUpload from schema definition config into runtime fields.
packages/react/src/components/F0Form/types.ts Adds useUpload?: UseFileUpload to all F0Form prop interfaces.
packages/react/src/components/F0Form/fields/file/types.ts Removes useUpload from F0FileConfig/F0FileField types.
packages/react/src/components/F0Form/fields/file/tests/FileFieldRenderer.test.tsx Removes some field-level useUpload usage (but still needs further updates).
packages/react/src/components/F0Form/fields/file/FileFieldRenderer.tsx Switches upload hook resolution from field.useUpload to context?.useUpload.
packages/react/src/components/F0Form/f0Schema.ts Removes inferring fieldType: "file" based on useUpload.
packages/react/src/components/F0Form/context.ts Adds useUpload?: UseFileUpload to F0FormContextValue.
packages/react/src/components/F0Form/components/F0FormSection.tsx Accepts/forwards useUpload into section-level context provider value.
packages/react/src/components/F0Form/stories/F0Form.stories.tsx Updates file-field stories to pass useUpload at the <F0Form> level.
packages/react/src/components/F0Form/F0Form.tsx Threads useUpload through all <F0Form> render paths into context.
Comments suppressed due to low confidence (1)

packages/react/src/components/F0Form/fields/file/tests/FileFieldRenderer.test.tsx:94

  • This test suite still has upload scenarios that don't provide a form-level useUpload prop, so selecting a file will never trigger an upload (and assertions like expecting signed_*.pdf will fail). Also, there is still at least one remaining useUpload usage inside a f0FormField config later in this file, which no longer matches the new API/type. Update these tests to pass useUpload={createMockUploadHook(...)} to <F0Form> and remove any remaining field-level useUpload config usage.
describe("FileFieldRenderer", () => {
  it("renders a dropzone with default text", () => {
    const schema = z.object({
      file: f0FormField(z.string().optional(), {
        label: "Document",
        fieldType: "file",
      }),
    })

    render(
      <F0Form
        name="test-file"
        schema={schema}
        defaultValues={{ file: "" }}
        onSubmit={async () => ({ success: true })}
      />
    )

@@ -183,8 +181,6 @@ export type F0FileField = F0BaseField & {
multiple?: boolean
/** Dropzone description text */
description?: string
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useUpload was removed from F0FileField, which makes standalone file fields (e.g. F0FormField where there is no F0FormContext.Provider) unable to upload at all. With the current FileFieldRenderer implementation relying on context, consumers have no way to supply an upload hook for standalone rendering. Consider either keeping useUpload on the runtime F0FileField for non-form usage, or adding a useUpload prop to F0FormField (and/or a way to inject it into context) so file uploads still work outside <F0Form>.

Suggested change
description?: string
description?: string
/**
* Consumer-provided upload hook.
*
* This is primarily used for standalone file fields rendered outside of
* `<F0Form>` / `F0FormContext.Provider`, where the upload hook cannot be
* supplied via context.
*/
useUpload?: UseFileUpload

Copilot uses AI. Check for mistakes.
Comment on lines 442 to 446
<FileUploadItem
key={entry.key}
entry={entry}
useUpload={entry.file ? field.useUpload : undefined}
useUpload={entry.file ? context?.useUpload : undefined}
onUploadComplete={(value) =>
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File uploads are now sourced from context?.useUpload, but when useUpload isn't provided the UI still lets users pick/drop files and then uploads never start (because FileUploadItem no-ops without an upload hook). Please add an explicit guard (e.g. hide/disable the dropzone when no useUpload is configured, or surface a clear error/throw when a new file is added) so misconfiguration doesn't fail silently.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix react Changes affect packages/react

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants