ranui
Version:
A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.
113 lines (112 loc) • 4.35 kB
TypeScript
import { EventManager } from '../../utils/builder';
import { RanElement } from '../../utils';
/** One file staged for sending. */
export interface Attachment {
/** Stable for this attachment's life; what `remove` takes and events report. */
id: string;
file: File;
name: string;
size: number;
type: string;
/**
* Object URL for an image preview, or null for anything else.
*
* An object URL, not a data URL: previewing costs a reference to bytes the browser
* already holds, while reading a 10 MB photo into a base64 string to show a 40px
* thumbnail costs the string. The data URL is built later, once, by whoever sends.
*/
previewUrl: string | null;
}
/** Why a file was not accepted. */
export type AttachmentRejection = 'too-large' | 'type-not-accepted' | 'too-many' | 'duplicate';
/**
* `<r-attachments>` — the files staged alongside a message.
*
* It holds the list, previews it, validates what arrives, and owns the object URLs it
* creates. It does not collect files: paste, drag-and-drop and a file picker are three
* gestures belonging to three different elements of a composer, and which of them an app
* offers is the app's decision. Call {@link add} from whichever it wires.
*
* ```ts
* const strip = document.querySelector('r-attachments');
* input.addEventListener('paste', (e) => {
* if (e.clipboardData?.files.length) strip.add(e.clipboardData.files);
* });
* strip.addEventListener('attachmentrejected', (e) => toast(explain(e.detail.reason)));
* ```
*
* **Rejection is reported, never silent.** A file that vanishes because it was 3 MB over a
* limit nobody mentioned reads as a bug in the page.
*
* Attributes: `accept` (as `<input accept>`), `max-size` (bytes), `max-count`, `sheet`.
* `count` is reflected so an empty strip can take no space.
*
* Events: `attachmentschange` (`{ attachments }`), `attachmentrejected`
* (`{ file, reason }`).
*/
export declare class Attachments extends RanElement {
_events: EventManager;
_shadowDom: ShadowRoot;
_list: HTMLElement;
private _attachments;
static get observedAttributes(): string[];
constructor();
/** The staged files, in the order they arrived. */
get attachments(): readonly Attachment[];
/** Just the files, for building a request body. */
get files(): File[];
/** Comma-separated types or extensions, in the form `<input accept>` takes. */
get accept(): string;
set accept(value: string);
/** Largest file accepted, in bytes. */
get maxSize(): number;
set maxSize(value: number);
/** Most files that may be staged at once; unlimited when unset. */
get maxCount(): number;
set maxCount(value: number);
get sheet(): string;
set sheet(value: string);
/**
* Stages files, rejecting what does not qualify.
*
* @param files Anything iterable of `File` — a `FileList` from a picker, a drop, or a
* paste.
* @returns The attachments that were accepted, in arrival order.
*/
add(files: Iterable<File>): Attachment[];
/**
* Removes one attachment and releases its preview.
*
* Named `detach` rather than `remove` because every element already has a `remove()` that
* takes no arguments and takes itself out of the document. Shadowing it with different
* semantics is a trap for anyone who reaches for the standard method.
*
* @param id The attachment id.
* @returns Whether anything was removed.
*/
detach(id: string): boolean;
/** Removes everything and releases every preview — what sending should call. */
clear(): void;
connectedCallback(): void;
disconnectedCallback(): void;
attributeChangedCallback(name: string, old: string | null, next: string | null): void;
handlerExternalCss: () => void;
private _release;
private _emit;
/**
* Decides whether a file may be staged.
*
* @param file The candidate.
* @returns The reason to refuse it, or null to accept.
*/
private _reject;
/**
* Matches a file against the `accept` list, the way a file picker does.
*
* @param file The candidate.
* @returns Whether its type or extension is listed.
*/
private _accepts;
private _render;
}
export default Attachments;