nl-design-system / rijkshuisstijl-community

Unofficial Rijkshuisstijl components and design tokens based on the NL Design System architecture. This project is not endorsed by the Dutch Ministry of General Affairs.
https://rijkshuisstijl-community.vercel.app/
European Union Public License 1.2
6 stars 3 forks source link

Bestand invoer component (zie comment design review) #449

Closed Robbert closed 5 days ago

Robbert commented 3 months ago

Figma Deze component bestaat uit een aantal componenten:

Robbert commented 3 months ago

Groningen en Den Haag hebben veel onderzoek gedaan, het zou handig zijn om daar een implementatie van te maken.

Rubenoo commented 2 months ago

@Robbert Kan ik ergens deze onderzoeken teruglezen/vinden?

Rerbun commented 1 month ago

590 is een eerste versie van dit component zonder de vereisten die in Slack zijn besproken en met styling gemaakt in Figma:

Gebruikte styling door team van Ruben O:

Image Image

Rerbun commented 1 month ago

BestandInvoer.tsx:

import { ChangeEvent, InputHTMLAttributes } from "react";
import { Control, Controller, FieldValues, Path } from "react-hook-form";
import { BestandWeergave } from "../../main";

export type BestandinvoerProps<TFieldValues extends FieldValues = FieldValues> = {
  name: Path<TFieldValues>;
  control: Control<TFieldValues>;
  uploadenLabel: string;
  verwijderLabel?: string;
} & InputHTMLAttributes<HTMLInputElement>;

/**
 * Om er voor te zorgen dat de implementerende kant gebruik kan maken van de BestandUpload
 * binnen formulieren die op verschillende wijze zijn opgezet zijn de props 'name' en
 * 'control' generiek. Hierdoor wijkt het Bestandinvoer component af qua declaratie ten
 * opzichte van andere componenten.
 *
 * Als het verwijderLabel niet meegegeven wordt, dan wordt er geen mogelijkheid tot het verwijderen van de input aangeboden.
 * @type FunctionComponent<BestandinvoerProps> - Type van het component is op deze wijze
 * nog steeds beschikbaar in Typescript en voor de IDE-omgeving.
 */
export const Bestandinvoer = <TFieldValues extends FieldValues>({
  name,
  control,
  uploadenLabel,
  verwijderLabel,
  ...options
}: BestandinvoerProps<TFieldValues>) => (
  <Controller
    name={name}
    control={control}
    render={({ field: { onChange, value } }) =>
      value ? (
        <BestandWeergave
          {...options}
          bestand={value}
          verwijderFunctie={onChange}
          verwijderLabel={verwijderLabel}
        />
      ) : (
        <div>
          <label>
            <input
              {...options}
              className="bestand-upload__file"
              type="file"
              onChange={(event: ChangeEvent<HTMLInputElement>) => {
                onChange(event.target.files![0]);
              }}
              value={value?.filename}
            />
            <span role="button" className="bestand-upload">
              {uploadenLabel}
            </span>
          </label>
        </div>
      )
    }
  />
);
Rerbun commented 1 month ago

BestandWeergave.tsx:

import { FunctionComponent, InputHTMLAttributes } from "react";
import { ReactComponent as BestandIcon } from "../../../icons/functioneel/66-bestand-icon.svg";

type FileType = {
  size: number;
  name: string;
  type: string;
};

export type BestandWeergaveProps = {
  bestand: File | FileType;
  verwijderLabel?: string;
  verwijderFunctie?: () => void;
} & InputHTMLAttributes<HTMLInputElement>;

export const BestandWeergave: FunctionComponent<BestandWeergaveProps> = ({
  bestand,
  verwijderLabel,
  verwijderFunctie,
  ...options
}) => {
  return (
    <div className="bestand-weergave" {...options}>
      <BestandIcon className="bestand-weergave__icon" />
      <div className="bestand-weergave__info">
        <div className="bestand-weergave__bestandnaam">
          <span className="bestand-weergave__bestandnaam-titel">{bestand.name}</span>
          <span className="bestand-weergave__bestandnaam-metadata">
            {bestand.type}, {formateerBytes(bestand.size)}
          </span>
        </div>
        {verwijderFunctie && verwijderLabel && (
          <button onClick={verwijderFunctie} className="btn btn-link">
            {verwijderLabel}
          </button>
        )}
      </div>
    </div>
  );
};

export const formateerBytes = (bytes: number): string => {
  const kilobytes = bytes / 1000;
  const megabytes = kilobytes / 1000;

  return megabytes >= 1 ? `${megabytes.toFixed(1)} MB` : `${kilobytes.toFixed(1)} KB`;
};
Rubenoo commented 1 month ago

Wij zijn momenteel wel bezig om dit bestand meerdere bestanden te laten uploaden met mogelijkheid tot compressie. Dat kunnen wij ook delen als dit af is

Rerbun commented 1 month ago

Nog een voorbeeld https://open-formulieren.github.io/open-forms-sdk/?path=/story/form-io-components-vanilla-fileupload--multiple-allowed-file-types

Robbert commented 1 month ago

Bij Open Formulieren wordt zo'n component ook al gebruikt:

https://open-formulieren.github.io/open-forms-sdk/?path=/story/form-io-components-vanilla-fileupload--one-allowed-file-type

https://github.com/open-formulieren/open-forms-sdk/blob/2633c1ffafb5f2e28b8b5de5a68d02150a96c25f/src/formio/templates/file.ejs#L110

Rerbun commented 1 month ago

https://github.com/orgs/nl-design-system/discussions/310

Rozerinay commented 5 days ago

Design review 1


Er is column-gap voor de afstand boven en onder de Button. Dit hoort row-gap te zijn.
Image


Waar komt de variant 'Met Custom Elementen Paragraaf en Accordion' vandaan?

Die verschilt redelijk ten opzichte van 'Met Custom Elementen Lijst'. Er is bijvoorbeeld een Heading 2 gebruikt en er is geen row-gap toegepast tussen de Heading, Paragraph en Accordion.
Image


Is het nodig om de variant 'Met Callback' in het overzicht te tonen?

Rozerinay commented 4 days ago

PR van Mees: https://github.com/nl-design-system/rijkshuisstijl-community/pull/804