UI Components

Message

One message of a conversation, nol-message, for the rows of a VirtualListComponent whose kind is VirtualListKind.Feed, where each row is an article. Its header shows the author's avatar, name and how long ago it was written, such as 2 minutes ago, in the app's LOCALE_ID, or the time of day, such as 14:05, with MessageTimeFormat.Clock; the time shows the date and time of day on hover and on focus, and one clock moves every message's time on each 30 seconds while any is shown. A hidden name of the author, date and time has the MessageComponent.labelId, so the feed's article is named by them. A message that continues the one before it hides its header and avatar. The person's own message can take MessageLayout.Bubble: its content in a bubble at the end side, at most 70% of the message's width, on the raised color with the medium radius, with no avatar or header, and under the bubble its Copy action and then its time, shown as the Copy action is. A conversation whose text lines up with its column takes MessageLayout.Column, whose header holds the parts the app projects with nolMessageHeader, such as a model name or a ChipKind.Status chip. In every layout the app adds its own actions before Copy with MessageActionDirective.

Its blocks follow in their order. Text is Markdown once the app adds provideMarkdown() from @noldova/ui.components.angular/markdown to its providers; without it, and until the parser has loaded, each text block shows as it was written, plain, with its Markdown marks. Markdown text is parsed with raw HTML left as text, and drawn as elements, never as HTML: an image is drawn by the app's MessageImageDirective template, or else shows its alt text, and only http, https and mailto addresses and those with a scheme the app names in MessageComponent.linkSchemes become links, which a click, a middle click or Enter hands to the app through MessageComponent.linkActivate and never follow; a link to a file's path, or to a file: URL on this machine, is a link only when MessageComponent.fileLinks is on, and goes to MessageComponent.fileActivate. Nesting deeper than 24 elements, 8 lists or 8 quotes is drawn at the deepest level, and text past 200,000 characters is shown plain. While the message streams, each of its text blocks that is not interim reveals a little at a time, in bursts about 50 ms apart and every frame once the message ends, as a Markdown view's streaming input says, holding back an unfinished end of at most 300 characters, and the parts already shown keep their elements, also when a slot comes before them, such as an activity row. A text block past the text blocks the message is first drawn with reveals from nothing; those it is drawn with show what they have at once. The part not yet shown is cut from the text, in every look, so a block such as a code block, or an inline code's chip, is laid out at the size of what it shows and grows with the reveal, and a screen reader and Copy see the text shown so far. While a selection reaches into a revealing text, all that has arrived shows at once. A list item that starts with a box, [ ] or [x], is a task that shows a box, empty or checked, which can't be changed. Code, a code block or fenced in the text, shows in a CodeBlockComponent up to 32rem high, then scrolls inside; attachments show as buttons; slots show the app's templates marked with MessageSlotDirective.

Its status shows in words beside an icon or a spinner: Writing, Cancelled, or the error's text with a Retry button. A message that streamed announces politely, with its author, that the reply is complete, or that it failed and its error, never its text; one shown already complete, or cancelled, doesn't, and one given a MessageComponent.key announces each end once however many of its rows see it. Each run of text and code taller than the message-collapsed-height look token, 24rem by default, or than MessageComponent.collapsedHeight, in a message that didn't stream in view, is collapsed with its own Show more button that expands it and then collapses it again; attachments and slots never collapse. While a reply streams, the app marks its feed VirtualListComponent.busy. Its Copy action, shown on hover and while the message or its article has focus, writes the blocks' text as Markdown through the ClipboardWriter and says Copied or Couldn't copy for 1.5 seconds. Escape from a control inside it returns the focus to its article, or to the feed when the article is a feed's, unless the control used Escape. A right click, the ContextMenu key or Shift+F10 asks the app for its context menu through MessageComponent.contextMenuRequest, unless the app shows a link's own menu through MessageComponent.linkMenu. Its text stays selectable.

Examples

Loading…

States

Loading…

API

Selector nol-message

Import from @noldova/ui.components.angular

Inputs

NameTypeDefaultDescription
authorMessageAuthor Required

Who wrote the message.

authorDescriptionstring | nullnull

A short description of the author, such as an agent's model, or null, the default, for none. Given one, the author's name and avatar show a TooltipDirective on hover, the name as its title and this description below it, and the name takes a focus stop that shows it too; the avatar stays out of the tab order. An empty description counts as none.

timeDate Required

When the message was written.

blocksreadonly MessageBlock[] Required

The message's content, in its order; a list without blocks, or with blank text only, shows "No text" once the message is no longer streaming.

statusMessageStatusMessageStatus.Complete

Where the message stands; MessageStatus.Complete when not bound.

errorstring | nullnull

The text shown for a failed message, or null, the default, for "The message couldn't be completed."

keystring | nullnull

The identity of the message's reply, such as its id and attempt, so its completion or failure is announced once even when its row is drawn again, or null, the default, to announce each end the message sees. A reply tried again takes a new key, or an end it repeats is not announced.

continuationbooleanfalse

Whether the message continues one by the same author, which hides its header and avatar; false when not bound.

selectedbooleanfalse

Whether the message is selected, which MessageComponent.selectionLook shows, and its name, through MessageComponent.labelId, ends with "selected"; false when not bound.

selectionLookMessageSelectionLookMessageSelectionLook.Bar

How the message shows that it is selected: a bar at its start and the selection color, or the raised background with large corners; MessageSelectionLook.Bar when not bound. It changes nothing while the message isn't selected.

headerbooleantrue

Whether a message in the column layout shows its header row: its avatar, its author's name, the parts the app projects with nolMessageHeader and, without its footer, its actions; true when not bound. Off, the column message draws no header, so it starts at its content, for an app that shows the author inside the content, such as a plan card's own header; with its footer off too, its actions show at its top end, as the row layout's do, over the content's first line, so the app keeps that corner of its content clear. A person's message in a column has no header either way. The row and bubble layouts always show theirs.

footerbooleantrue

Whether a message in the column layout shows its footer row: its actions, such as Copy, its time and any MessageFooterEndDirective content; true when not bound. Off, the column message draws no footer, so it ends at its content, for a list such as a view of a chat's plans, and shows its actions in its header instead, after the app's header content, when they show in the footer, on the header's line without making it taller, or on a row of their own under the header's content, which the header grows by, when that line has no room left for them. A person's message in a column, which has no header, shows no actions with it off. The row and bubble layouts always show it.

actionsTopstring | nullnull

How far below the message's top edge its top actions stand, as a CSS length, such as calc(var(--nol-space-2) + 0.25rem), or null, the default, for 0.25rem. The top actions are the row layout's and those of a column message with both its header and its footer off, so an app that shows its author inside the content, such as a plan card's own header, can center them on that header's line. Actions in a header or a footer row keep their place.

actionsEndstring | nullnull

How far from the message's end edge its top actions stand, as a CSS length, such as calc(var(--nol-space-2) + 0.5rem), or null, the default, for 0.5rem. It moves the same actions as actionsTop, so an app that shows its author inside the content, such as a plan card's own header, can set the actions' gap to that header's end. Actions in a header or a footer row keep their place.

flashStartDate | nullnull

When the message's flash started, such as when the app took the person to it, or null, the default, for no flash. From that time the message fades an accent tint from its bubble, from a box with a bubble's corners and padding around a column message's header and content, or from its row or its selected Raised fill, once over 1.6 seconds, a Highlight outline under forced colors. The app keeps the time, so a message drawn again, such as a recycled row, or shown again goes on with the flash where it was; null stops the flash, and a new time plays it again from that time. Its label stays the same.

labelIdstring | nullnull

The id of the element that names the message with its author and time, such as a feed row's labelId, or null, the default, for none.

collapsedHeightnumber | nullnull

The height in rem past which each run of text and code collapses, or null, the default, for the theme's message-collapsed-height.

layoutMessageLayoutMessageLayout.Row

How the message lays out, a row with its avatar and header or the person's bubble; MessageLayout.Row when not bound. A bubble's MessageComponent.continuation only drops its top padding.

timeFormatMessageTimeFormatMessageTimeFormat.Relative

How the message writes its time, how long ago or the time of day, in the app's LOCALE_ID; MessageTimeFormat.Relative when not bound. Either way the time's tooltip and name give the date and time of day. provideTimeFormats gives the time of day, and the date and time, in the app's own formats.

twentyFourHourbooleanfalse

Whether the message writes the time of day on a 24-hour clock, such as 09:05 and 16:01, whatever the locale's own clock, in its time and in the date and time of its tooltip and name; false when not bound, which follows the locale. An app that writes its own times as HH:mm turns it on, so a message shows the same time as the app's panels. A format from provideTimeFormats takes its place for the time it writes.

mentionsreadonly MentionCandidate[][]

The people and agents whose mentions the message's text marks, as the mention field's candidates; none when not bound. Each @name of one shows as the markdown view's mentions input says.

mentionNamesbooleantrue

Whether the message's text marks each @name of one of its MessageComponent.mentions; true when not bound. When false, it marks only the links to mention:<id>, as the markdown view's mentionNames input says.

copyTextstring | nullnull

The text the Copy action writes, or null, when not bound, for the message's text blocks, joined by blank lines, interim answers left out. An app that draws part of the message itself, such as an error in a slot or the text between a reply's steps, gives the whole text here.

fileLinksbooleanfalse

Whether a link to a file's path in the message's text, or to a file: URL on this machine, is a link, which starts with the FileBadgeComponent for its path, without a # or ? part after it, as the Markdown view's fileLinks input says; false when not bound, and then a link to a path shows its text plain and one to a file: URL shows as written. It means what the Markdown view's fileLinks input from @noldova/ui.components.angular/markdown means.

linkSchemesMarkdownLinkSchemesMarkdownLinkSchemes.none

The link schemes of the app's own that the message's text makes links of, which go to MessageComponent.linkActivate; MarkdownLinkSchemes.none when not bound. It means what the Markdown view's linkSchemes input from @noldova/ui.components.angular/markdown means.

folderLinksReadonlySet<string>new Set()

The paths of the message's file links that are folders, in the form MessageComponent.fileActivate emits them; a file link whose path is in the set shows the folder mark in place of its file badge. Empty when not bound. It means what the Markdown view's folderLinks input from @noldova/ui.components.angular/markdown means.

referencesILinkReferenceSource | nullnull

The app's reader of links to items on code hosts, which draws each link it knows in the message's text as a LinkReference chip, and with ILinkReferenceSource.findText each reference it finds written in the text; null, the default, keeps every link plain. It means what the Markdown view's references input from @noldova/ui.components.angular/markdown means.

shellRunsbooleanfalse

Whether the message's shell code blocks, in its text and its own code blocks, offer Run before Copy once the message has stopped streaming; false when not bound, and then they have no Run. It means what CodeBlockComponent.runnable means, and Run stays hidden while MessageComponent.status is MessageStatus.Streaming, so code still being written is never run. In its text, Run never shows on a block whose fence never closed, as a reply cut off mid-block leaves it.

shellRunStatesReadonlyMap<number, ShellRunState>new Map()

What became of each shell block's latest Run, keyed by ShellRun.block, which its Run shows as ShellRunState says; a block it doesn't name is Idle. Empty when not bound.

shellRunOutputsReadonlySet<number>new Set()

The code blocks, by ShellRun.block, under which the message draws the app's ShellRunOutputDirective template, such as a terminal the block's Run opened. The template's content spans the message's text column, from its start to its end, whatever the block's own indent in a list or a quote, and follows the block, as far below it as the text's blocks are apart. Empty when not bound, or with no template, and then nothing shows and the message's layout is today's.

mathbooleantrue

Whether the message's text draws math; true when not bound. It means what the Markdown view's math input from @noldova/ui.components.angular/markdown means, so an app turns it off for a person's own message, whose $$ is often a shell's, and leaves it on for a reply.

Outputs

NameTypeDescription
copiedstring

Emits the text the Copy action, named "Copy message", wrote to the clipboard.

retryvoid

Emits when the person asks to try a failed message again. A message in the error status shows its Retry button only while something listens to this output, such as a (retry) binding or a subscription, and Retry comes and goes with the listeners; a host that cannot retry binds nothing and shows the error alone.

attachmentOpenstring

Emits the id of the attachment the person chooses.

linkActivatestring

Emits the address of the link the person chooses; the app decides what opens.

linkOpenLinkOpenEvent

Emits each link the person opens in the message's text, beside the address MessageComponent.linkActivate gives: its address, how it was opened and the event, as the Markdown view's linkOpen says.

linkMenuLinkMenuEvent

Emits each link in the message's text the person asks the menu of, by a right-click, the ContextMenu key or Shift+F10, as the Markdown view's linkMenu says; when the app cancels the event's default in its handler, before it returns, to show its own menu, the message asks for none through MessageComponent.contextMenuRequest, so each press gives one menu.

fileActivatestring

Emits the target of the file link the person chooses while MessageComponent.fileLinks is on, in the form the Markdown view's fileActivate output from @noldova/ui.components.angular/markdown gives it: the path itself, decoded, which the app uses as it is and resolves.

filePathsChangereadonly string[]

Emits the paths of the file links the message's text shows, in the form MessageComponent.fileActivate emits them, each once, in the order of the text, whenever that list changes, including while a reply streams, so the app learns which of them are folders without reading the Markdown itself. Nothing is emitted while the list stays empty, and the list is empty while MessageComponent.fileLinks is off. A Markdown view the app puts in a slot adds none of its paths.

shellRunShellRun

Emits the code, language and index of the shell block whose Run the person chooses while MessageComponent.shellRuns is on, whatever its state; the kit never runs it, and the app decides what running means.

contextMenuRequestMessageMenuRequest

Emits where to open the app's context menu for the message: at the pointer on a right click, or below the focused part on the ContextMenu key or Shift+F10. The browser's own menu doesn't open over a message, and the message stops each event it answers, so a context-menu trigger around it, as in the example, opens once, on the part that had the focus, and gives the focus back to it.

Accessibility

KeyAction
TabMoves the focus to the message's time, a link in its text and its actions; the actions are one Tab stop, onto the action focused last.
Arrow RightIn the actions, moves to the next action.
Arrow LeftIn the actions, moves to the previous action.
HomeMoves to the first action, the owner's own when it adds one.
EndMoves to the last action, Copy.
EnterPresses the focused action, or Retry.
SpacePresses the focused action, or Retry.
EscapeFrom a part of the message, moves the focus to the article it sits in, or to the feed when that article is a row of a feed.
Shift+F10Asks the owner, through contextMenuRequest, for its menu below the focused part; the browser's own menu doesn't open.
Context MenuAsks the owner for its menu as Shift+F10 does.

Its owner names it through labelId: a hidden label with that id reads its author, date and time, ending in selected while it is selected, for the article around it to point aria-labelledby at.

Its actions are a toolbar named "Message actions": the owner's nolMessageAction buttons, then Copy, named "Copy message", and "Copied" for a moment after it copies.

Its time is a focus stop whose name and tooltip give the date and time of day; the avatar is hidden from screen readers beside the author's name.

A failed message shows its error after a hidden glyph, with a Retry button only while its owner listens to retry, so a message its owner can't retry shows no control that does nothing.

A reply that streamed announces, politely, its author and that it is complete or failed, never its text, and Copy announces Copied.

A right-click, Shift+F10 or the Context Menu key asks its owner for a menu for the part that has the focus, and the message stops the event, so a context menu trigger around it opens once.

Specification

Loading…