Data

Images

Pictures in place, held at their shape while they load: ImageThumbnail caps a tall one and keeps a small one at its own size. A click opens ImageViewer: zoom, ← → through the group's pictures, Esc. ImageSourcesProvider says where a message's local pictures come from and whether another site's load.

Live example

Import

Each family is its own entry point, so a page loads only what it uses.

tsx
import { ImageSourcesProvider } from "@nibapp/ui/components/image-sources";import { ImageThumbnail } from "@nibapp/ui/components/image-thumbnail";import { ImageGallery, ImageGroup } from "@nibapp/ui/components/image-viewer";import { Markdown } from "@nibapp/ui/components/markdown";import { RemoteImageCard } from "@nibapp/ui/components/remote-image-gate";

Props

Each component's own props and variants, read from its source. What it also takes from an element or a Base UI part is named below its table.

ImageSourcesProvider

PropTypeDefaultDescription
value (required)ImageSources—
children (required)ReactNode—

ImageThumbnail

An image in a message list, as an image: proportional, never larger than its own size or the column, at most 320 px tall (160 in a row of them), so a tall screenshot never takes over the page. A click opens it full size (the gallery's viewer). While it loads, a placeholder holds the place; one that can't load, or is too large to show, says so in its place.

PropTypeDefaultDescription
src (required)string | undefined—

What `<img>` loads (inline data, a blob or an object URL); undefined while the host fetches it.

alt (required)string—

What it shows: the text alternative, and what the viewer is titled.

namestring | undefined—

The file name Save suggests.

captionReactNode—

A quiet line under the picture (where it came from).

problemImageProblem | undefined—
size"md" | "sm" | undefined"md"

`md`: one image in its place (up to 320 px tall); `sm`: one of a row of them (up to 160 px).

widthnumber | undefined—

Its own size (`imageSize`, from its header), when known: the place is held at its shape.

heightnumber | undefined—
galleryKeystring | undefined—

Which image it is in its gallery (the host's list of a turn's images); default its `src`.

classNamestring | undefined—

ImageGallery

Where images open together: a thumbnail's click opens the viewer on it, and ← → step through the other images of its group (`ImageGroup`, a turn), in reading order. Without one, an image opens on its own.

PropTypeDefaultDescription
imagesOf((group: string) => readonly ViewerImage[]) | undefined—

A group's images (a turn's) in reading order, from the host's own data, so ← → reach the ones scrolled out of view too; without it (or for an image it doesn't list), the ones on screen.

children (required)ReactNode—

ImageGroup

The images below open together in the gallery (a turn's).

PropTypeDefaultDescription
id (required)string—
children (required)ReactNode—

Markdown

Assistant-message renderer: GFM, Shiki code blocks, calm prose rhythm. While the text streams it shows whole blocks, never letters: a block shows once it is finished (a fence line by line, a list item by item, a long paragraph sentence by sentence), blocks that finish together follow one another in order, and what is new fades in (opacity only; not under reduced motion). History never moves.

PropTypeDefaultDescription
children (required)string—

Markdown source.

streamingbooleanfalse

The text is still arriving: repairs unfinished syntax and only re-renders the last block.

measurebooleanfalse

Constrain line length to a comfortable ~72ch measure.

allowImageHostsreadonly string[] | undefined—

Remote image hosts trusted to load on render (e.g. the host's own CDN). Other http(s) images show a "Load image" placeholder until the reader asks; data:, blob: and same-origin always load.

codeActionsCodeBlockActions | undefined—

Extra controls for each finished code block (none by default).

Also takes the props of a <div> element, except children.

RemoteImageCard

A remote image where the page may not load one (a page whose CSP keeps other sites' images out, so a message can't fetch, and leak, anything by rendering): what it is and where it lives, and the link to open it in the browser.

PropTypeDefaultDescription
src (required)string—
alt (required)string—
host (required)string—