File
file seleciona um arquivo local e persiste apenas o valor string | number retornado pelo executor. O objeto File do navegador é usado somente para transporte; ele nunca é armazenado em DyonaFormValues.
Testar ao vivo
Contrato do field
Um field File exige uploadSource.sourceId. accept é opcional e contém as extensões ou tipos MIME aceitos por esse schema; DYONA não impõe uma whitelist. maxFileSizeBytes é opcional e deve ser um número finito positivo.
{
name: 'document',
label: 'Documento',
type: 'file',
required: true,
uploadSource: {sourceId: 'documents'},
accept: ['.pdf', '.jpg', '.jpeg', '.png', '.webp', '.xls', '.xlsx', '.csv', '.doc', '.docx', '.txt'],
maxFileSizeBytes: 10_000_000,
}
O controle valida o arquivo selecionado contra accept e maxFileSizeBytes antes de iniciar o envio.
Executor, progresso e cancelamento
Informe fileUploadExecutor ao DyonaForm. Ele recebe o arquivo, um AbortSignal, um callback de progresso 0..100 e dados de contexto do field. O controle mostra progresso determinado e expõe Cancelar durante o envio. O cancelamento preserva o value persistido anterior.
DYONA Form não implementa backend nem transporte: a aplicação consumidora define HTTP, autenticação, armazenamento, tentativas e validação do servidor.
Exemplo completo
import {useCallback, useState} from 'react';
import {DyonaForm, type DyonaFileUploadExecutor, type DyonaFormSchema, type DyonaFormValues} from '@typhonsoftware/dyona-form';
const schema: DyonaFormSchema = {
title: 'Envio de documento', hideSingleTab: true,
tabs: [{id: 'documents', title: 'Documento', rows: [{columns: [{
name: 'document', label: 'Documento', type: 'file', required: true,
uploadSource: {sourceId: 'documents'},
accept: ['.pdf', '.jpg', '.jpeg', '.png', '.webp', '.xls', '.xlsx', '.csv', '.doc', '.docx', '.txt'],
maxFileSizeBytes: 10_000_000,
}]}]}],
};
export function DocumentForm() {
const [submittedValues, setSubmittedValues] = useState<DyonaFormValues | null>(null);
const fileUploadExecutor = useCallback<DyonaFileUploadExecutor>((request) => new Promise((resolve, reject) => {
let progress = 0;
let timer: number | null = null;
const cancel = () => {
if (timer !== null) window.clearInterval(timer);
reject(new DOMException('Envio cancelado', 'AbortError'));
};
if (request.signal.aborted) return cancel();
request.signal.addEventListener('abort', cancel, {once: true});
request.onProgress(0);
timer = window.setInterval(() => {
progress += 10;
request.onProgress(progress);
if (progress === 100) {
window.clearInterval(timer!);
request.signal.removeEventListener('abort', cancel);
resolve({value: 'FILE-DEMO-001'});
}
}, 160);
}), []);
return <>
<DyonaForm schema={schema} fileUploadExecutor={fileUploadExecutor} onSubmit={setSubmittedValues} />
{submittedValues && <pre>{JSON.stringify(submittedValues, null, 2)}</pre>}
</>;
}
Após um envio bem-sucedido, onSubmit recebe o value persistido:
{document: 'FILE-DEMO-001'}