UNPKG

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
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;