Hopp til innhold

File­Input

Filinput lar brukeren dele filer med oss, for eksempel dokumentasjon i en sak.

Kom i gang

Installer
npm i @fremtind/jkl-file-input-react
Bruk
import { FileInput, File } from "@fremtind/jkl-file-input-react";
import "@fremtind/jkl-file-input/file-input.min.css";
import "@fremtind/jkl-button/button.min.css";
import "@fremtind/jkl-icon-button/icon-button.min.css";
import "@fremtind/jkl-icons/icons.min.css";
import "@fremtind/jkl-input-group/input-group.min.css";
import "@fremtind/jkl-progress-bar/progress-bar.min.css";
React
Versjon
Dokumentasjon
Readme
Changelog

Live demo

FileInput
Egenskaper
Variant
Label
Visning
Tema
Tetthet
const FakeProgressBar = () => {
const [hasMounted, setHasMounted] = React.useState(false);
React.useEffect(() => {
setHasMounted(true);
}, []);
const [progress, setProgress] = React.useState(0);
React.useEffect(() => {
setTimeout(() => {
setProgress((p) => (p < 100 ? p + 1 : p));
}, 20);
}, [progress, setProgress]);
const isTestMode =
hasMounted && window.location.search === "?mode=e2e" ? "e2e" : undefined;
return <ProgressBar aria-valuenow={isTestMode ? 50 : progress} />;
};
const FileInputExample = () => {
const [files, setFiles] = React.useState([]);
const maxSizeBytes = 8_000_000;
return (
<div>
<FileInput
legend="Vedlegg"
labelProps={{ variant: 'small' }}
className="jkl-spacing-16-24--bottom"
accept="image/*,.pdf"
maxSizeBytes={maxSizeBytes}
value={files}
variant={'flexible'}
onChange={(e, newFiles) => {
setFiles((currentFiles) => [...currentFiles, ...newFiles]);
}}
>
{files.map(({ state, file, validation }, index) => {
let label = undefined;
let labelType = undefined;
let demoState = state;
const lasterOpp = false;
const isUploading = lasterOpp || state === "UPLOADING";
const valideringsfeil = false;
const lastetOpp = false;
const medFeil = false;
if (valideringsfeil || validation?.type === "WRONG_TYPE") {
labelType = "warning";
label = `Filtypen ${file.name?.split(".")[1] || ""} støttes ikke`;
} else if (lastetOpp || state === "UPLOAD_SUCCESS") {
labelType = "success";
label = "Lastet opp";
demoState = "UPLOAD_SUCCESS";
} else if (medFeil || state === "UPLOAD_ERROR") {
labelType = "error";
label = "Filen lot seg ikke laste opp";
demoState = "UPLOAD_ERROR";
} else if (validation?.type === "TOO_LARGE") {
labelType = "error";
label = `Filen er større enn ${formatBytes(
maxSizeBytes
)} og kan ikke lastes opp`;
} else if (isUploading) {
label = "Laster opp…";
demoState = "UPLOADING";
}
return (
<File
key={file.name}
fileName={file.name}
fileType={file.type}
fileSize={file.size}
file={file}
state={demoState}
supportLabel={label}
supportLabelType={labelType}
onRemove={
["UPLOAD_ERROR", "SELECTED"].includes(state)
? () => {
setFiles([
...files.slice(0, index),
...files.slice(index + 1),
]);
}
: undefined
}
>
{isUploading && <FakeProgressBar />}
</File>
);
})}
</FileInput>
<PrimaryButton
className="jkl-spacing-16--top"
type="button"
onClick={async () => {
const toUpload = files.filter(
(fileState) =>
fileState.state === "SELECTED" &&
typeof fileState.validation === "undefined"
);
const promises = toUpload.map(
(fileState, i) =>
new Promise((resolve) => {
const timeout = 2_000;
setTimeout(() => {
setFiles((currentState) => {
return [
...currentState.slice(0, i),
{ ...currentState[i], state: "UPLOAD_SUCCESS" },
...currentState.slice(i + 1),
];
});
resolve();
}, timeout);
})
);
const newFiles = files.map((file) =>
toUpload.includes(file) ? { ...file, state: "UPLOADING" } : file
);
setFiles(newFiles);
await Promise.all(promises);
}}
>
Last opp
</PrimaryButton>
</div>
);
};
render(<FileInputExample />);

Håndtering av delte filer

Hva skjer når brukeren starter opplastingen av filer? Detaljene er opp til hvert enkelt team, men grovt sett trengs:

  • Et endepunkt som leser multi-part form data, og som klarer dekode filinformasjonen i skjemaet.
  • Et sted å lagre filene på disk. Dette trenger ikke være samme maskin som endepunktet.
  • Ett eller flere endepunkt som kan spørres for å se filer brukeren har delt med oss tidligere, for eksempel tilknyttet en sak.

Det finnes en upload-funksjon du kan importere fra denne pakka for å få hjelp med å sende filene til backend og beregne fremdriften.

Det finnes også en eksempelapp som inkluderer en backend som du kan se på, men sørg for å lese disclaimeren i README-filen først.

Forhåndsvisning av fil

Forhåndsvisning av fil
Visning
Tema
Tetthet
const files = [
{
name: "icon.png",
type: "image/png",
size: 66610000,
publicPath: "/media/macos-filvelger-morkt.webp",
},
];
return (
<>
<p className="jkl-heading-4">Vedlegg til saken</p>
<ul style={{ listStyle: "none", margin: 0, padding: 0 }}>
{files.map((file) => (
<li key={file.name}>
<File
fileName={file.name}
fileType={file.type}
fileSize={file.size}
path={file.publicPath}
/>
</li>
))}
</ul>
</>
);

React API

Her finner du en oversikt over props på komponentene i pakken.