feat(form-fill): FormFill tool with context and UI components for PDF form filling (#5711)

This commit is contained in:
Balázs Szücs
2026-02-13 15:10:48 +00:00
committed by GitHub
parent 5a1ed50e2b
commit 27bd34c29b
35 changed files with 4481 additions and 92 deletions
@@ -0,0 +1,20 @@
/**
* FormFieldOverlay stub for the core build.
* This file is overridden in src/proprietary/tools/formFill/FormFieldOverlay.tsx
* when building the proprietary variant.
*/
interface FormFieldOverlayProps {
documentId: string;
pageIndex: number;
pageWidth: number;
pageHeight: number;
fileId?: string | null;
}
export function FormFieldOverlay(_props: FormFieldOverlayProps) {
// Core build stub — renders nothing
return null;
}
export default FormFieldOverlay;
@@ -0,0 +1,17 @@
/**
* FormFieldSidebar stub for the core build.
* This file is overridden in src/proprietary/tools/formFill/FormFieldSidebar.tsx
* when building the proprietary variant.
*/
interface FormFieldSidebarProps {
visible: boolean;
onToggle: () => void;
}
export function FormFieldSidebar(_props: FormFieldSidebarProps) {
// Core build stub — renders nothing
return null;
}
export default FormFieldSidebar;
@@ -0,0 +1,85 @@
/**
* FormFillProvider stub for the core build.
* This file is overridden in src/proprietary/tools/formFill/FormFillContext.tsx
* when building the proprietary variant.
*/
import React, { createContext, useContext } from 'react';
interface FormFillContextValue {
state: {
fields: any[];
values: Record<string, string>;
loading: boolean;
error: string | null;
activeFieldName: string | null;
isDirty: boolean;
validationErrors: Record<string, string>;
};
fetchFields: (file: File | Blob, fileId?: string) => Promise<void>;
setValue: (fieldName: string, value: string) => void;
setActiveField: (fieldName: string | null) => void;
submitForm: (file: File | Blob, flatten?: boolean) => Promise<Blob>;
getField: (fieldName: string) => any | undefined;
getFieldsForPage: (pageIndex: number) => any[];
getValue: (fieldName: string) => string;
validateForm: () => boolean;
reset: () => void;
fieldsByPage: Map<number, any[]>;
activeProviderName: string;
setProviderMode: (mode: 'pdflib' | 'pdfbox') => void;
forFileId: string | null;
}
const noopAsync = async () => {};
const noop = () => {};
const FormFillContext = createContext<FormFillContextValue | null>(null);
export const useFormFill = (): FormFillContextValue => {
const ctx = useContext(FormFillContext);
if (!ctx) {
// Return a default no-op value for core builds
return {
state: {
fields: [],
values: {},
loading: false,
error: null,
activeFieldName: null,
isDirty: false,
validationErrors: {},
},
fetchFields: noopAsync,
setValue: noop,
setActiveField: noop,
submitForm: async () => new Blob(),
getField: () => undefined,
getFieldsForPage: () => [],
getValue: () => '',
validateForm: () => true,
reset: noop,
fieldsByPage: new Map(),
activeProviderName: 'none',
setProviderMode: noop,
forFileId: null,
};
}
return ctx;
};
/** No-op stub for core builds */
export function useFieldValue(_fieldName: string): string {
return '';
}
/** No-op stub for core builds */
export function useAllFormValues(): Record<string, string> {
return {};
}
export function FormFillProvider({ children }: { children: React.ReactNode }) {
// In core build, just render children without provider
return <>{children}</>;
}
export default FormFillContext;
@@ -0,0 +1,17 @@
/**
* FormSaveBar stub for the core build.
* This file is overridden in src/proprietary/tools/formFill/FormSaveBar.tsx
* when building the proprietary variant.
*/
interface FormSaveBarProps {
file: File | Blob | null;
isFormFillToolActive: boolean;
onApply?: (filledBlob: Blob) => Promise<void>;
}
export function FormSaveBar(_props: FormSaveBarProps) {
return null;
}
export default FormSaveBar;