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
| Name | Type | Default | Description |
|---|---|---|---|
author | MessageAuthor | Required | Who wrote the message. |
authorDescription | string | null | 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 |
time | Date | Required | When the message was written. |
blocks | readonly 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. |
status | MessageStatus | MessageStatus.Complete | Where the message stands; |
error | string | null | The text shown for a failed message, or null, the default, for "The message couldn't be completed." |
key | string | null | 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. |
continuation | boolean | false | Whether the message continues one by the same author, which hides its header and avatar; false when not bound. |
selected | boolean | false | Whether the message is selected, which |
selectionLook | MessageSelectionLook | MessageSelectionLook.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; |
header | boolean | true | Whether a message in the column layout shows its header row: its avatar, its author's name, the parts the app projects with |
footer | boolean | true | Whether a message in the column layout shows its footer row: its actions, such as Copy, its time and any |
actionsTop | string | null | How far below the message's top edge its top actions stand, as a CSS length, such as |
actionsEnd | string | null | How far from the message's end edge its top actions stand, as a CSS length, such as |
flashStart | Date | null | 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 |
labelId | string | null | The id of the element that names the message with its author and time, such as a feed row's |
collapsedHeight | number | null | The height in rem past which each run of text and code collapses, or null, the default, for the theme's |
layout | MessageLayout | MessageLayout.Row | How the message lays out, a row with its avatar and header or the person's bubble; |
timeFormat | MessageTimeFormat | MessageTimeFormat.Relative | How the message writes its time, how long ago or the time of day, in the app's |
twentyFourHour | boolean | false | 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 |
mentions | readonly MentionCandidate[] | [] | The people and agents whose mentions the message's text marks, as the mention field's candidates; none when not bound. Each |
mentionNames | boolean | true | Whether the message's text marks each |
copyText | string | null | 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. |
fileLinks | boolean | false | Whether a link to a file's path in the message's text, or to a |
linkSchemes | MarkdownLinkSchemes | MarkdownLinkSchemes.none | The link schemes of the app's own that the message's text makes links of, which go to |
folderLinks | ReadonlySet<string> | new Set() | The paths of the message's file links that are folders, in the form |
references | ILinkReferenceSource | null | The app's reader of links to items on code hosts, which draws each link it knows in the message's text as a |
shellRuns | boolean | false | 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 |
shellRunStates | ReadonlyMap<number, ShellRunState> | new Map() | What became of each shell block's latest Run, keyed by |
shellRunOutputs | ReadonlySet<number> | new Set() | The code blocks, by |
math | boolean | true | Whether the message's text draws math; true when not bound. It means what the Markdown view's |
Outputs
| Name | Type | Description |
|---|---|---|
copied | string | Emits the text the Copy action, named "Copy message", wrote to the clipboard. |
retry | void | 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 |
attachmentOpen | string | Emits the id of the attachment the person chooses. |
linkActivate | string | Emits the address of the link the person chooses; the app decides what opens. |
linkOpen | LinkOpenEvent | Emits each link the person opens in the message's text, beside the address |
linkMenu | LinkMenuEvent | 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 |
fileActivate | string | Emits the target of the file link the person chooses while |
filePathsChange | readonly string[] | Emits the paths of the file links the message's text shows, in the form |
shellRun | ShellRun | Emits the code, language and index of the shell block whose Run the person chooses while |
contextMenuRequest | MessageMenuRequest | 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
| Key | Action |
|---|---|
| Tab | Moves 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 Right | In the actions, moves to the next action. |
| Arrow Left | In the actions, moves to the previous action. |
| Home | Moves to the first action, the owner's own when it adds one. |
| End | Moves to the last action, Copy. |
| Enter | Presses the focused action, or Retry. |
| Space | Presses the focused action, or Retry. |
| Escape | From 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+F10 | Asks the owner, through contextMenuRequest, for its menu below the focused part; the browser's own menu doesn't open. |
| Context Menu | Asks 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…