@dxos/react-ui-thread 0.11.0 → 0.12.0-next-2800d0376abcc62d5544afdd744b16b2b960434e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/index.mjs +9 -7
- package/dist/lib/index.mjs.map +1 -1
- package/dist/types/src/Message/Message.d.ts +47 -48
- package/dist/types/src/Message/Message.d.ts.map +1 -1
- package/dist/types/src/Message/Message.stories.d.ts +3 -2
- package/dist/types/src/Message/Message.stories.d.ts.map +1 -1
- package/dist/types/src/Thread/Thread.d.ts +23 -30
- package/dist/types/src/Thread/Thread.d.ts.map +1 -1
- package/dist/types/src/Thread/Thread.stories.d.ts +3 -2
- package/dist/types/src/Thread/Thread.stories.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +1 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -21
- package/src/Message/Message.tsx +14 -3
- package/src/Thread/Thread.tsx +2 -1
package/dist/lib/index.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { translationKey } from "./translations.mjs";
|
|
2
1
|
import { format } from "date-fns/format";
|
|
3
2
|
import { startOfDay } from "date-fns/startOfDay";
|
|
4
3
|
import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
@@ -7,6 +6,7 @@ import { Avatar, Icon, IconButton, ScrollArea, composable, composableProps, useO
|
|
|
7
6
|
import { Mosaic } from "@dxos/react-ui-mosaic";
|
|
8
7
|
import { createBasicExtensions, createThemeExtensions, keymap, listener, tags } from "@dxos/ui-editor";
|
|
9
8
|
import { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx } from "@dxos/ui-theme";
|
|
9
|
+
import { translationKey } from "#translations";
|
|
10
10
|
import { HighlightStyle, StreamLanguage, syntaxHighlighting } from "@codemirror/language";
|
|
11
11
|
import { EditorView } from "@codemirror/view";
|
|
12
12
|
import { createContext } from "@radix-ui/react-context";
|
|
@@ -152,13 +152,14 @@ var TextBlock = ({ block, isAuthor, editing, onSave }) => {
|
|
|
152
152
|
const handleDocumentChange = useCallback((next) => {
|
|
153
153
|
inMemoryContentRef.current = next;
|
|
154
154
|
}, []);
|
|
155
|
-
|
|
155
|
+
const saveDocumentChange = useCallback(() => {
|
|
156
156
|
onSave?.(inMemoryContentRef.current);
|
|
157
|
-
}, [onSave])
|
|
157
|
+
}, [onSave]);
|
|
158
|
+
useOnTransition(editing, true, false, saveDocumentChange);
|
|
158
159
|
const { parentRef, focusAttributes, view } = useTextEditor(() => ({
|
|
159
160
|
initialValue: block.text,
|
|
160
161
|
extensions: [
|
|
161
|
-
createBasicExtensions({ readOnly: !
|
|
162
|
+
createBasicExtensions({ readOnly: !editing }),
|
|
162
163
|
createThemeExtensions({ themeMode }),
|
|
163
164
|
command,
|
|
164
165
|
EditorView.updateListener.of((update) => {
|
|
@@ -166,9 +167,9 @@ var TextBlock = ({ block, isAuthor, editing, onSave }) => {
|
|
|
166
167
|
})
|
|
167
168
|
]
|
|
168
169
|
}), [
|
|
169
|
-
block.text,
|
|
170
170
|
editing,
|
|
171
|
-
|
|
171
|
+
editing ? void 0 : block.text,
|
|
172
|
+
editing ? void 0 : isAuthor,
|
|
172
173
|
themeMode,
|
|
173
174
|
handleDocumentChange
|
|
174
175
|
]);
|
|
@@ -225,6 +226,7 @@ var MessageTextbox = forwardRef(({ id, authorId, authorName, authorImgSrc, autho
|
|
|
225
226
|
continues: false,
|
|
226
227
|
children: /* @__PURE__ */ jsx("div", {
|
|
227
228
|
ref: parentRef,
|
|
229
|
+
"data-testid": "thread.reply",
|
|
228
230
|
className: mx("py-0.5 me-1 rounded-xs dx-focus-ring", disabled && "opacity-50"),
|
|
229
231
|
...focusAttributes
|
|
230
232
|
})
|
|
@@ -610,7 +612,7 @@ var ThreadItemAdapter = ({ id, data, location, draggable, current, selected }) =
|
|
|
610
612
|
})
|
|
611
613
|
});
|
|
612
614
|
var DEFAULT_GROUP_WINDOW_MS = 6e4;
|
|
613
|
-
var DEFAULT_GAP_DIVIDER_MS =
|
|
615
|
+
var DEFAULT_GAP_DIVIDER_MS = 108e5;
|
|
614
616
|
/** Virtualized stack of message tiles (via Mosaic), within an internal scroll area. */
|
|
615
617
|
var ThreadMessages = ({ messages, id, estimateSize = 80, currentId, groupWindowMs = DEFAULT_GROUP_WINDOW_MS, dayDivider = true, gapDividerMs = DEFAULT_GAP_DIVIDER_MS, classNames }) => {
|
|
616
618
|
const { dtLocale } = useTranslation(translationKey);
|
package/dist/lib/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/command.ts","../../src/context.ts","../../src/Message/Message.tsx","../../src/Thread/Thread.tsx"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { HighlightStyle, StreamLanguage, syntaxHighlighting } from '@codemirror/language';\nimport { type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\nimport { tags } from '@dxos/ui-editor';\nimport { mx } from '@dxos/ui-theme';\n\n/**\n * Highlights leading slash-commands (e.g. `/resolve`) and `@mention` tags\n * (e.g. `@Kai`, anywhere) in the message composer.\n * https://github.com/codemirror/stream-parser/blob/main/test/test-stream-parser.ts\n */\nconst parser = StreamLanguage.define<{ count: number }>({\n startState: () => ({ count: 0 }),\n token: (stream, state) => {\n state.count++;\n if (stream.eatSpace()) {\n return null;\n }\n // Leading slash-command (first token only).\n if (state.count === 1 && stream.match(/^\\/\\w+/)) {\n return 'tagName';\n }\n // @mention (anywhere).\n if (stream.match(/^@\\w+/)) {\n return 'labelName';\n }\n stream.next();\n return null;\n },\n});\n\nconst styles = HighlightStyle.define([\n {\n tag: tags.tagName,\n class: mx('dx-tag dx-tag--indigo'),\n },\n {\n tag: tags.labelName,\n class: mx('dx-tag dx-tag--blue'),\n },\n]);\n\n// Center the inline `.dx-tag` pills on the text line. `.dx-tag` is `inline-block`\n// with vertical padding, so on a CodeMirror line it baseline-aligns and rides\n// high; overriding `vertical-align` recentres it (cf. the `cm-reference-pill`\n// precedent in `@dxos/react-ui-chat`).\nconst theme = EditorView.theme({\n '.dx-tag': {\n verticalAlign: 'bottom',\n },\n});\n\nexport const command: Extension = [parser, syntaxHighlighting(styles), theme];\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { createContext } from '@radix-ui/react-context';\nimport { type FC, type ReactNode } from 'react';\n\n// Imported so TypeScript can name this type in the emitted .d.ts (ThreadContext → Message).\n// eslint-disable-next-line unused-imports/no-unused-imports\nimport { type Message } from '@dxos/types';\n\nimport { type ThreadContextValue } from './types';\n\n/**\n * Context provided by `Thread.Root` and consumed by its parts. Extends the\n * consumer-facing {@link ThreadContextValue} with internal coordination (e.g.\n * focusing the composer from the header's select affordance).\n */\nexport type ThreadContext = ThreadContextValue & {\n /** Register the composer's focus handler (set by `Thread.Textbox`). */\n registerComposerFocus: (focus: (() => void) | undefined) => void;\n /** Focus the thread composer (used by `Thread.Header`'s select affordance). */\n focusComposer: () => void;\n};\n\nexport const [ThreadContextProvider, useThreadContext]: readonly [\n FC<ThreadContext & { children: ReactNode }>,\n (consumerName: string) => ThreadContext,\n] = createContext<ThreadContext>('Thread');\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { EditorView } from '@codemirror/view';\nimport { format } from 'date-fns/format';\nimport React, {\n type ComponentPropsWithoutRef,\n type ComponentPropsWithRef,\n type ReactNode,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\n\nimport { Obj, Ref } from '@dxos/echo';\nimport {\n Avatar,\n IconButton,\n type ThemedClassName,\n useOnTransition,\n useThemeContext,\n useTranslation,\n} from '@dxos/react-ui';\nimport { type UseTextEditorProps, useTextEditor } from '@dxos/react-ui-editor';\nimport { type ContentBlock, type Message as MessageType } from '@dxos/types';\nimport { createBasicExtensions, createThemeExtensions, keymap, listener } from '@dxos/ui-editor';\nimport { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx } from '@dxos/ui-theme';\nimport { hexToEmoji, hexToHue, isTruthy } from '@dxos/util';\n\nimport { command } from '../command';\nimport { useThreadContext } from '../context';\nimport { translationKey } from '../translations';\nimport { type MessageMetadata } from '../types';\n\nconst avatarSize = 7;\n\nconst buttonGroupClassNames = 'flex flex-row items-center gap-0.5 pe-2';\nconst buttonClassNames = 'p-1! transition-opacity';\n\n//\n// Root\n//\n\nexport type MessageRootProps = ThemedClassName<\n ComponentPropsWithRef<'div'> & MessageMetadata & Partial<{ continues: boolean; controls: ReactNode }>\n>;\n\n// TODO(burdon): Show authorName on tooltip.\nconst MessageRoot = forwardRef<HTMLDivElement, MessageRootProps>(\n (\n {\n authorImgSrc,\n authorId,\n authorName,\n authorAvatarProps,\n continues = true,\n controls,\n children,\n classNames,\n ...rootProps\n },\n forwardedRef,\n ) => {\n // Must wrap the message since Avatar.Label may be used in the content.\n // Columns mirror Thread.Header (avatar/rail · content · controls) so trailing\n // controls align with the thread header's controls.\n return (\n <Avatar.Root>\n <div\n data-testid='thread.message'\n {...rootProps}\n className={mx('grid grid-cols-[var(--dx-rail-size)_1fr_min-content] w-full', classNames)}\n ref={forwardedRef}\n >\n <div className='flex flex-col items-center gap-2 pt-1'>\n <Avatar.Content\n size={avatarSize}\n hue={authorAvatarProps?.hue || hexToHue(authorId ?? '0')}\n fallback={authorAvatarProps?.emoji || hexToEmoji(authorId ?? '0')}\n {...(authorImgSrc && { imgSrc: authorImgSrc })}\n />\n {continues && <div className='w-px grow bg-separator' />}\n </div>\n <div className='py-1 min-w-0'>{children}</div>\n {controls && <div className='self-start'>{controls}</div>}\n </div>\n </Avatar.Root>\n );\n },\n);\n\nMessageRoot.displayName = 'Message.Root';\n\n//\n// Heading\n//\n\nexport type MessageHeadingProps = ThemedClassName<ComponentPropsWithoutRef<'div'>> &\n Pick<MessageMetadata, 'authorName' | 'timestamp'>;\n\nconst MessageHeading = ({ children, classNames, timestamp, authorName, ...props }: MessageHeadingProps) => {\n return (\n <div {...props} className={mx('flex gap-2 items-start', classNames)}>\n <p className='grow flex items-baseline gap-2 min-w-0'>\n <MessageAuthorName authorName={authorName} />\n {timestamp && <MessageTime timestamp={timestamp} />}\n </p>\n {children}\n </div>\n );\n};\n\nMessageHeading.displayName = 'Message.Heading';\n\nexport type MessageAuthorNameProps = Pick<MessageMetadata, 'authorName'>;\n\nconst MessageAuthorName = ({ authorName }: MessageAuthorNameProps) => {\n const { t } = useTranslation(translationKey);\n return (\n <Avatar.Label classNames='block truncate min-w-0 shrink text-sm text-subdued'>\n {authorName ?? t('anonymous.label')}\n </Avatar.Label>\n );\n};\n\nMessageAuthorName.displayName = 'Message.AuthorName';\n\nexport type MessageTimeProps = Pick<MessageMetadata, 'timestamp'>;\n\nconst MessageTime = ({ timestamp }: MessageTimeProps) => {\n const { dtLocale } = useTranslation(translationKey);\n const dt = timestamp ? new Date(timestamp) : undefined;\n return (\n <time className='shrink-0 text-subdued text-xs' dateTime={dt?.toISOString()}>\n {dt ? format(dt, 'p', { locale: dtLocale }) : ''}\n </time>\n );\n};\n\nMessageTime.displayName = 'Message.Time';\n\n//\n// Body\n//\n\nexport type MessageBodyProps = {\n /** The message whose content blocks are rendered. */\n message: MessageType.Message;\n /** When true, the local user authored this message. */\n isAuthor?: boolean;\n /** When true, the text block is editable. */\n editing?: boolean;\n /** Persist an edited text block. */\n onSave?: (text: string) => void;\n};\n\n/**\n * Renders a message's content blocks: text (via editor), proposal, and\n * object/reference tiles (delegated to the injected `Object` component).\n */\nconst MessageBody = ({ message, isAuthor, editing, onSave }: MessageBodyProps) => {\n const { components } = useThreadContext('Message.Body');\n const textBlockIndex = message.blocks.findIndex((block) => block._tag === 'text');\n const textBlock = textBlockIndex !== -1 ? (message.blocks[textBlockIndex] as ContentBlock.Text) : undefined;\n const proposalBlock = message.blocks.find((block) => block._tag === 'proposal') as ContentBlock.Proposal | undefined;\n const changeBlock = message.blocks.find((block) => block._tag === 'change') as ContentBlock.Change | undefined;\n const references = message.blocks\n .filter((block) => block._tag === 'reference')\n .map((block) => (block as ContentBlock.Reference).reference);\n const Object = components.Object;\n\n return (\n <>\n {textBlock && <TextBlock block={textBlock} isAuthor={isAuthor} editing={editing} onSave={onSave} />}\n {proposalBlock && <div className='me-4 italic'>{proposalBlock.text}</div>}\n {changeBlock && (\n <p className='me-4 text-sm break-words'>\n {changeBlock.before && <span className='line-through opacity-60'>{changeBlock.before}</span>}\n {changeBlock.before && changeBlock.after && ' '}\n {changeBlock.after && <span>{changeBlock.after}</span>}\n </p>\n )}\n {Object &&\n Ref.Array.targets(references).map((reference, index) => (\n <Object key={index} subject={reference as Obj.Unknown} />\n ))}\n </>\n );\n};\n\nMessageBody.displayName = 'Message.Body';\n\nconst TextBlock = ({\n block,\n isAuthor,\n editing,\n onSave,\n}: {\n block: ContentBlock.Text;\n isAuthor?: boolean;\n editing?: boolean;\n onSave?: (text: string) => void;\n}) => {\n const { themeMode } = useThemeContext();\n const inMemoryContentRef = useRef(block.text);\n\n const handleDocumentChange = useCallback((next: string) => {\n inMemoryContentRef.current = next;\n }, []);\n\n const saveDocumentChange = useCallback(() => {\n onSave?.(inMemoryContentRef.current);\n }, [onSave]);\n\n useOnTransition(editing, true, false, saveDocumentChange);\n\n const { parentRef, focusAttributes, view } = useTextEditor(\n () => ({\n initialValue: block.text,\n extensions: [\n createBasicExtensions({ readOnly: !isAuthor || !editing }),\n createThemeExtensions({ themeMode }),\n command,\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n handleDocumentChange(update.state.doc.toString());\n }\n }),\n ],\n }),\n [block.text, editing, isAuthor, themeMode, handleDocumentChange],\n );\n\n useEffect(() => {\n if (editing) {\n view?.focus();\n }\n }, [editing, view]);\n\n return <div ref={parentRef} className='me-4' {...focusAttributes} />;\n};\n\n//\n// Textbox\n//\n\nexport type MessageTextboxProps = {\n disabled?: boolean;\n onSend?: () => void;\n onClear?: () => void;\n onEditorFocus?: () => void;\n} & MessageMetadata &\n UseTextEditorProps;\n\nconst keyBindings = ({ onSend, onClear }: Pick<MessageTextboxProps, 'onSend' | 'onClear'>) => [\n {\n key: 'Enter',\n run: () => {\n if (onSend) {\n onSend();\n return true;\n }\n return false;\n },\n },\n {\n key: 'Meta+Backspace',\n run: () => {\n if (onClear) {\n onClear();\n return true;\n }\n return false;\n },\n },\n];\n\nexport type MessageTextboxHandle = { focus: () => void };\n\nconst MessageTextbox = forwardRef<MessageTextboxHandle, MessageTextboxProps>(\n (\n {\n id,\n authorId,\n authorName,\n authorImgSrc,\n authorAvatarProps,\n disabled,\n extensions,\n onSend,\n onClear,\n onEditorFocus,\n ...editorProps\n },\n forwardedRef,\n ) => {\n const { parentRef, focusAttributes, view } = useTextEditor(\n () => ({\n id,\n extensions: [\n keymap.of(keyBindings({ onSend, onClear })),\n listener({\n onFocus: ({ focusing }) => {\n if (focusing) {\n onEditorFocus?.();\n }\n },\n }),\n extensions,\n ].filter(isTruthy),\n ...editorProps,\n }),\n [id, extensions],\n );\n\n useImperativeHandle(forwardedRef, () => ({ focus: () => view?.focus() }), [view]);\n\n return (\n <MessageRoot {...{ id, authorId, authorName, authorImgSrc, authorAvatarProps }} continues={false}>\n <div\n ref={parentRef}\n className={mx('py-0.5 me-1 rounded-xs dx-focus-ring', disabled && 'opacity-50')}\n {...focusAttributes}\n />\n </MessageRoot>\n );\n },\n);\n\nMessageTextbox.displayName = 'Message.Textbox';\n\n//\n// Tile\n//\n\nexport type MessageTileProps = {\n message: MessageType.Message;\n classNames?: MessageRootProps['classNames'];\n /** Whether the avatar-rail continuation line is drawn below the tile; false for the last tile. */\n continues?: boolean;\n};\n\n/**\n * Full message tile (frame + heading + controls + body). Reads `Thread.Root`\n * context for metadata resolution, injected renderers, and callbacks. This is\n * the unit rendered by `Thread.Messages`.\n */\nconst MessageTile = ({ message, classNames, continues = true }: MessageTileProps) => {\n const { t } = useTranslation(translationKey);\n const {\n getMetadata,\n identityDid,\n editable,\n onMessageDelete,\n onAcceptProposal,\n onAcceptChange,\n onRejectChange,\n onMessageSelect,\n currentMessageId,\n } = useThreadContext('Message.Tile');\n const [editing, setEditing] = useState(false);\n\n const metadata = getMetadata(message);\n const isAuthor = !!identityDid && identityDid === metadata.authorId;\n const hasProposal = message.blocks.some((block) => block._tag === 'proposal');\n const hasChange = message.blocks.some((block) => block._tag === 'change');\n\n const handleEdit = useCallback(() => setEditing((value) => !value), []);\n const handleDelete = useCallback(() => onMessageDelete?.(message.id), [onMessageDelete, message.id]);\n const handleAcceptProposal = useCallback(() => onAcceptProposal?.(message.id), [onAcceptProposal, message.id]);\n const handleAcceptChange = useCallback(() => onAcceptChange?.(message.id), [onAcceptChange, message.id]);\n const handleRejectChange = useCallback(() => onRejectChange?.(message.id), [onRejectChange, message.id]);\n const handleSelect = useCallback(() => onMessageSelect?.(message.id), [onMessageSelect, message.id]);\n const handleSave = useCallback(\n (text: string) => {\n Obj.update(message, (message) => {\n const block = message.blocks.find((block) => block._tag === 'text');\n if (block && block._tag === 'text') {\n block.text = text;\n }\n });\n },\n [message],\n );\n\n const showEdit = isAuthor && editable;\n const showAccept = hasProposal && !!onAcceptProposal;\n const showAcceptChange = hasChange && !!onAcceptChange;\n const showRejectChange = hasChange && !!onRejectChange;\n const showDelete = !!onMessageDelete;\n const controls =\n showEdit || showAccept || showAcceptChange || showRejectChange || showDelete ? (\n <div className={buttonGroupClassNames}>\n {showEdit && (\n <IconButton\n data-testid={editing ? 'thread.message.save' : 'thread.message.edit'}\n variant='ghost'\n icon={editing ? 'ph--check--regular' : 'ph--pencil-simple--regular'}\n iconOnly\n label={t(editing ? 'save-message.label' : 'edit-message.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleEdit}\n />\n )}\n {showAccept && (\n <IconButton\n data-testid='thread.message.accept'\n variant='ghost'\n icon='ph--check--regular'\n iconOnly\n label={t('accept-proposal.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleAcceptProposal}\n />\n )}\n {showAcceptChange && (\n <IconButton\n data-testid='thread.message.accept-change'\n variant='ghost'\n icon='ph--check--regular'\n iconOnly\n label={t('accept-change.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleAcceptChange}\n />\n )}\n {showRejectChange && (\n <IconButton\n data-testid='thread.message.reject-change'\n variant='ghost'\n icon='ph--x--regular'\n iconOnly\n label={t('reject-change.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleRejectChange}\n />\n )}\n {showDelete && (\n <IconButton\n data-testid='thread.message.delete'\n variant='ghost'\n icon='ph--x--regular'\n iconOnly\n label={t('delete-message.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleDelete}\n />\n )}\n </div>\n ) : undefined;\n\n return (\n <MessageRoot\n {...metadata}\n continues={continues}\n controls={controls}\n // Selecting a tile is how the host reveals what it refers to (a suggestion's range in the\n // document), so the whole tile is the target — the accent marks which one is showing.\n onClick={onMessageSelect ? handleSelect : undefined}\n aria-current={currentMessageId === message.id ? 'location' : undefined}\n classNames={[\n hoverableControls,\n hoverableFocusedWithinControls,\n onMessageSelect && 'cursor-pointer',\n currentMessageId === message.id && 'bg-current-surface',\n classNames,\n ]}\n >\n <MessageHeading authorName={metadata.authorName} timestamp={metadata.timestamp} />\n <MessageBody message={message} isAuthor={isAuthor} editing={editing} onSave={handleSave} />\n </MessageRoot>\n );\n};\n\nMessageTile.displayName = 'Message.Tile';\n\n//\n// Group\n//\n\nexport type MessageGroupProps = {\n /** Consecutive same-sender messages, in ascending time order, rendered as one tile. */\n messages: readonly MessageType.Message[];\n /** Whether the avatar-rail continuation line is drawn below the tile; false for the last tile. */\n continues?: boolean;\n classNames?: MessageRootProps['classNames'];\n};\n\n/**\n * Groups consecutive same-sender messages (see `Thread.Messages`'s grouping\n * window) into a single tile: one heading (author + first message's\n * timestamp) followed by one body per message, stacked in order. Per-message\n * edit/delete controls are not shown per-row in a group — v1 shows them for\n * the group's first message only, since the heading/controls layout is keyed\n * to a single message.\n */\nconst MessageGroup = ({ messages, continues = true, classNames }: MessageGroupProps) => {\n const { t } = useTranslation(translationKey);\n const { getMetadata, identityDid, editable, onMessageDelete, onAcceptProposal } = useThreadContext('Message.Group');\n const [editing, setEditing] = useState(false);\n\n const first = messages[0];\n const metadata = getMetadata(first);\n const isAuthor = !!identityDid && identityDid === metadata.authorId;\n const hasProposal = first.blocks.some((block) => block._tag === 'proposal');\n\n const handleEdit = useCallback(() => setEditing((value) => !value), []);\n const handleDelete = useCallback(() => onMessageDelete?.(first.id), [onMessageDelete, first.id]);\n const handleAcceptProposal = useCallback(() => onAcceptProposal?.(first.id), [onAcceptProposal, first.id]);\n const handleSave = useCallback(\n (text: string) => {\n Obj.update(first, (first) => {\n const block = first.blocks.find((block) => block._tag === 'text');\n if (block && block._tag === 'text') {\n block.text = text;\n }\n });\n },\n [first],\n );\n\n const showEdit = isAuthor && editable;\n const showAccept = hasProposal && !!onAcceptProposal;\n const showDelete = !!onMessageDelete;\n const controls =\n showEdit || showAccept || showDelete ? (\n <div className={buttonGroupClassNames}>\n {showEdit && (\n <IconButton\n data-testid={editing ? 'thread.message.save' : 'thread.message.edit'}\n variant='ghost'\n icon={editing ? 'ph--check--regular' : 'ph--pencil-simple--regular'}\n iconOnly\n label={t(editing ? 'save-message.label' : 'edit-message.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleEdit}\n />\n )}\n {showAccept && (\n <IconButton\n data-testid='thread.message.accept'\n variant='ghost'\n icon='ph--check--regular'\n iconOnly\n label={t('accept-proposal.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleAcceptProposal}\n />\n )}\n {showDelete && (\n <IconButton\n data-testid='thread.message.delete'\n variant='ghost'\n icon='ph--x--regular'\n iconOnly\n label={t('delete-message.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleDelete}\n />\n )}\n </div>\n ) : undefined;\n\n return (\n <MessageRoot\n {...metadata}\n continues={continues}\n controls={controls}\n classNames={[hoverableControls, hoverableFocusedWithinControls, classNames]}\n >\n <MessageHeading authorName={metadata.authorName} timestamp={metadata.timestamp} />\n {messages.map((message) => (\n <MessageBody\n key={message.id}\n message={message}\n isAuthor={isAuthor}\n editing={editing && message === first}\n onSave={handleSave}\n />\n ))}\n </MessageRoot>\n );\n};\n\nMessageGroup.displayName = 'Message.Group';\n\n//\n// Message\n//\n\nexport const Message = {\n Root: MessageRoot,\n Heading: MessageHeading,\n AuthorName: MessageAuthorName,\n Time: MessageTime,\n Body: MessageBody,\n Textbox: MessageTextbox,\n Tile: MessageTile,\n Group: MessageGroup,\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { format } from 'date-fns/format';\nimport { type Locale } from 'date-fns/locale';\nimport { startOfDay } from 'date-fns/startOfDay';\nimport React, {\n type ComponentPropsWithRef,\n type PropsWithChildren,\n type ReactNode,\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { Obj } from '@dxos/echo';\nimport {\n type ComposableProps,\n Icon,\n IconButton,\n ScrollArea,\n type ThemedClassName,\n composable,\n composableProps,\n useThemeContext,\n useTranslation,\n} from '@dxos/react-ui';\nimport { type DndContainerHandler } from '@dxos/react-ui-dnd';\nimport { Mosaic, type MosaicTileProps } from '@dxos/react-ui-mosaic';\nimport { type Message as MessageType } from '@dxos/types';\nimport { type Extension, createBasicExtensions, createThemeExtensions, listener } from '@dxos/ui-editor';\nimport { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx } from '@dxos/ui-theme';\n\nimport { command } from '../command';\nimport { ThreadContextProvider, useThreadContext } from '../context';\nimport { Message } from '../Message';\nimport { translationKey } from '../translations';\nimport { type MessageMetadata, type ThreadContextValue } from '../types';\n\nconst getMessageId = (message: MessageType.Message) => Obj.getURI(message);\n\n//\n// Root\n//\n\nexport type ThreadRootProps = PropsWithChildren<\n Omit<ThreadContextValue, 'components'> & Partial<Pick<ThreadContextValue, 'components'>>\n>;\n\n/**\n * Headless root of a thread. Provides message-tile context (metadata resolver,\n * injected renderers, callbacks). Requires an ambient `Dnd.Root` ancestor,\n * within which `Thread.Messages` renders its virtual stack. Renders no DOM of\n * its own — wrap the visible thread chrome in `Thread.Content`.\n */\nconst ThreadRoot = ({\n children,\n getMetadata,\n components,\n identityDid,\n editable,\n onMessageDelete,\n onAcceptProposal,\n onAcceptChange,\n onRejectChange,\n onMessageSelect,\n currentMessageId,\n}: ThreadRootProps) => {\n // Composer focus handler registered by Thread.Textbox; invoked by Thread.Header's caret.\n const composerFocus = useRef<(() => void) | undefined>(undefined);\n\n const registerComposerFocus = useCallback((focus: (() => void) | undefined) => {\n composerFocus.current = focus;\n }, []);\n\n const focusComposer = useCallback(() => composerFocus.current?.(), []);\n\n return (\n <ThreadContextProvider\n getMetadata={getMetadata}\n components={components ?? {}}\n identityDid={identityDid}\n editable={editable}\n registerComposerFocus={registerComposerFocus}\n focusComposer={focusComposer}\n onMessageDelete={onMessageDelete}\n onAcceptProposal={onAcceptProposal}\n onAcceptChange={onAcceptChange}\n onRejectChange={onRejectChange}\n onMessageSelect={onMessageSelect}\n currentMessageId={currentMessageId}\n >\n {children}\n </ThreadContextProvider>\n );\n};\n\nThreadRoot.displayName = 'Thread.Root';\n\n//\n// Content\n//\n\ntype ThreadContentExtra = {\n id?: string;\n current?: boolean | string;\n} & Pick<ComponentPropsWithRef<'div'>, 'onClickCapture' | 'onFocusCapture'>;\n\nexport type ThreadContentProps = ComposableProps<ThreadContentExtra>;\n\n/** Visible thread container (the attention surface that hosts header / messages / composer). */\nconst ThreadContent = composable<HTMLDivElement, ThreadContentExtra>(\n ({ children, current, id, ...props }, forwardedRef) => {\n return (\n <div\n {...composableProps(props, {\n role: 'group',\n classNames: [\n 'flex flex-col bg-[var(--surface-bg)] current-related dx-attention-surface [--controls-opacity:0]',\n hoverableFocusedWithinControls,\n ],\n })}\n data-testid='thread'\n id={id}\n aria-current={current ? 'location' : undefined}\n ref={forwardedRef}\n >\n {children}\n </div>\n );\n },\n);\n\nThreadContent.displayName = 'Thread.Content';\n\n//\n// Header\n//\n\nexport type ThreadHeaderProps = Omit<\n ComposableProps<{\n /** Snippet text rendered inside a `<p>` (a string, not a DOM element). */\n title?: string;\n detached?: boolean;\n /** Whether this is the current/selected thread; accents the title. */\n current?: boolean;\n /** Trailing controls rendered in the right column (aligns with message-tile controls). */\n controls?: ReactNode;\n /** Invoked when the caret affordance is activated to select/focus this thread. */\n onSelect?: () => void;\n }>,\n 'children'\n>;\n\n/**\n * Thread header row: caret (rail) · snippet (content) · controls. Owns its own\n * `[rail · 1fr · controls]` grid so the trailing controls align with message-tile\n * controls (which use the same template) — no grid is leaked in from the caller.\n */\nconst ThreadHeader = composable<HTMLDivElement, ThreadHeaderProps>(\n ({ title, detached, current, controls, onSelect, ...props }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n const { focusComposer } = useThreadContext('Thread.Header');\n const handleSelect = useCallback(() => {\n onSelect?.();\n focusComposer();\n }, [onSelect, focusComposer]);\n\n return (\n <div\n {...composableProps(props, {\n classNames: [\n 'grid grid-cols-[var(--dx-rail-size)_1fr_min-content] items-center',\n hoverableControls,\n hoverableFocusedWithinControls,\n ],\n })}\n ref={forwardedRef}\n >\n <div className='flex items-center justify-center'>\n <IconButton\n iconOnly\n variant='ghost'\n density='sm'\n icon='ph--caret-double-right--regular'\n label={t('select-thread.label')}\n classNames='text-description'\n onClick={handleSelect}\n />\n </div>\n <div className='flex items-center overflow-hidden'>\n <p\n role='heading'\n data-testid='thread.heading'\n className={mx(\n 'me-2 font-medium truncate italic',\n current ? 'text-accent-text' : 'text-description',\n detached && 'line-through decoration-1',\n )}\n >\n {title}\n </p>\n </div>\n {controls}\n </div>\n );\n },\n);\n\nThreadHeader.displayName = 'Thread.Header';\n\n//\n// Messages\n//\n\n/** A run of consecutive same-sender messages (within the grouping window) rendered as one tile. */\ntype MessageGroupItem = { kind: 'group'; id: string; messages: MessageType.Message[]; last?: boolean };\n\n/**\n * A divider row between groups: day-labeled (calendar-day boundary) or plain\n * (a same-day gap exceeding `gapDividerMs`). Day boundaries take priority\n * when both coincide on the same message — see `groupMessages`.\n */\ntype DividerItem = { kind: 'divider'; id: string; label?: string };\n\ntype ThreadItem = MessageGroupItem | DividerItem;\n\nconst getThreadItemId = (item: ThreadItem) => item.id;\n\n/** Stable per-sender key: prefers the DID, then the (deprecated) identity key, then name/email, else 'anon'. */\nconst senderKey = (message: MessageType.Message): string =>\n message.sender.identityDid ?? message.sender.identityKey ?? message.sender.name ?? message.sender.email ?? 'anon';\n\n/** Message send time in epoch ms; malformed/missing `created` sorts as if sent at the epoch. */\nconst messageTime = (message: MessageType.Message): number => {\n const time = Date.parse(message.created);\n return Number.isFinite(time) ? time : 0;\n};\n\n/**\n * Preprocesses ascending, time-ordered `messages` into a flat list of divider\n * and group items for `Thread.Messages`'s virtual stack:\n * - A day divider (labeled with the calendar date) precedes the first message\n * of each calendar day.\n * - A plain divider (no label) marks a same-day gap exceeding `gapDividerMs`.\n * - When both would fall on the same message, only the day divider is emitted.\n * - Consecutive messages from the same sender within `groupWindowMs` of the\n * previous message in the group are merged into one `MessageGroupItem`; a\n * divider always starts a new group.\n */\nconst groupMessages = (\n messages: readonly MessageType.Message[],\n {\n groupWindowMs,\n dayDivider,\n gapDividerMs,\n dtLocale,\n }: { groupWindowMs: number; dayDivider: boolean; gapDividerMs: number; dtLocale?: Locale },\n): ThreadItem[] => {\n const items: ThreadItem[] = [];\n let currentGroup: MessageGroupItem | undefined;\n // Tracks the last message appended to `currentGroup`, since `Array.prototype.at(-1)`\n // on `currentGroup.messages` would need a non-null assertion despite `currentGroup`\n // always being non-empty by construction.\n let lastGroupMessage: MessageType.Message | undefined;\n let prevTime: number | undefined;\n let prevDay: number | undefined;\n\n for (const message of messages) {\n const time = messageTime(message);\n const day = startOfDay(time).getTime();\n\n const dayBoundary = dayDivider && (prevDay === undefined || day !== prevDay);\n const gapBoundary = !dayBoundary && prevTime !== undefined && time - prevTime > gapDividerMs;\n\n if (dayBoundary) {\n items.push({\n kind: 'divider',\n id: `divider:day:${day}`,\n label: format(day, 'EEEE, MMMM d', { locale: dtLocale }),\n });\n currentGroup = undefined;\n } else if (gapBoundary) {\n items.push({ kind: 'divider', id: `divider:gap:${time}` });\n currentGroup = undefined;\n }\n\n const sameSenderAsGroup = currentGroup && lastGroupMessage && senderKey(lastGroupMessage) === senderKey(message);\n const withinGroupWindow = currentGroup && lastGroupMessage && time - messageTime(lastGroupMessage) <= groupWindowMs;\n\n if (currentGroup && sameSenderAsGroup && withinGroupWindow) {\n currentGroup.messages.push(message);\n } else {\n currentGroup = { kind: 'group', id: getMessageId(message), messages: [message] };\n items.push(currentGroup);\n }\n lastGroupMessage = message;\n\n prevTime = time;\n prevDay = day;\n }\n\n // The trailing group is the last message tile; suppress its avatar-rail continuation line.\n if (currentGroup) {\n currentGroup.last = true;\n }\n\n return items;\n};\n\n//\n// Divider\n//\n\nconst ThreadDivider = ({ label }: { label?: string }) =>\n label ? (\n <div className='flex items-center gap-2 px-2 py-2 text-xs text-description'>\n <div className='h-px grow bg-separator' />\n <span className='shrink-0'>{label}</span>\n <div className='h-px grow bg-separator' />\n </div>\n ) : (\n <div className='px-2 py-2'>\n <div className='h-px bg-separator' />\n </div>\n );\n\nThreadDivider.displayName = 'Thread.Divider';\n\nconst ThreadItemAdapter = ({ id, data, location, draggable, current, selected }: MosaicTileProps<ThreadItem>) => (\n <Mosaic.Tile id={id} data={data} location={location} draggable={draggable} current={current} selected={selected}>\n {data.kind === 'divider' ? (\n <ThreadDivider label={data.label} />\n ) : (\n <Message.Group messages={data.messages} continues={!data.last} />\n )}\n </Mosaic.Tile>\n);\n\nexport type ThreadMessagesProps = ThemedClassName<{\n messages: readonly MessageType.Message[];\n /** Stable id of the owning thread; scopes the Mosaic container so multiple threads don't collide. */\n id?: string;\n /** Estimated tile height for the virtualizer. */\n estimateSize?: number;\n currentId?: string;\n /** Consecutive same-sender messages within this window (ms) are merged into one tile. */\n groupWindowMs?: number;\n /** Whether to insert a labeled divider before the first message of each calendar day. */\n dayDivider?: boolean;\n /** A same-day gap exceeding this (ms) inserts an unlabeled divider between groups. */\n gapDividerMs?: number;\n}>;\n\nconst DEFAULT_GROUP_WINDOW_MS = 60_000;\nconst DEFAULT_GAP_DIVIDER_MS = 3 * 60 * 60 * 1000;\n\n/** Virtualized stack of message tiles (via Mosaic), within an internal scroll area. */\nconst ThreadMessages = ({\n messages,\n id,\n estimateSize = 80,\n currentId,\n groupWindowMs = DEFAULT_GROUP_WINDOW_MS,\n dayDivider = true,\n gapDividerMs = DEFAULT_GAP_DIVIDER_MS,\n classNames,\n}: ThreadMessagesProps) => {\n const { dtLocale } = useTranslation(translationKey);\n const [viewport, setViewport] = useState<HTMLElement | null>(null);\n const items = useMemo(\n () => groupMessages(messages.filter(Boolean), { groupWindowMs, dayDivider, gapDividerMs, dtLocale }),\n [messages, groupWindowMs, dayDivider, gapDividerMs, dtLocale],\n );\n // Per-instance id keeps concurrent threads (incl. the same thread mounted twice) distinct in the DnD registry.\n const instanceId = useId();\n const eventHandler = useMemo<DndContainerHandler>(\n () => ({ id: `thread:${id ?? 'anon'}:${instanceId}`, canDrop: () => false }),\n [id, instanceId],\n );\n\n return (\n <Mosaic.Container\n asChild\n orientation='vertical'\n autoScroll={viewport}\n currentId={currentId}\n eventHandler={eventHandler}\n >\n <ScrollArea.Root classNames={mx('col-span-2 flex-1 min-h-0', classNames)} orientation='vertical'>\n <ScrollArea.Viewport ref={setViewport}>\n <Mosaic.VirtualStack\n Tile={ThreadItemAdapter}\n items={items}\n getId={getThreadItemId}\n draggable={false}\n getScrollElement={() => viewport}\n estimateSize={() => estimateSize}\n />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </Mosaic.Container>\n );\n};\n\nThreadMessages.displayName = 'Thread.Messages';\n\n//\n// Textbox\n//\n\nexport type ThreadTextboxProps = MessageMetadata & {\n placeholder?: string;\n autoFocus?: boolean;\n disabled?: boolean;\n extensions?: Extension;\n /**\n * Called with the composer content on send. Return `true` to accept (the\n * editor is cleared and remounted), `false` to reject.\n */\n onSend?: (text: string) => boolean;\n};\n\n/** Message composer pinned at the foot of a thread. */\nconst ThreadTextbox = ({ placeholder, autoFocus, disabled, extensions, onSend, ...metadata }: ThreadTextboxProps) => {\n const { t } = useTranslation(translationKey);\n const { themeMode } = useThemeContext();\n const { registerComposerFocus } = useThreadContext('Thread.Textbox');\n const composerRef = useRef<{ focus: () => void } | null>(null);\n const messageRef = useRef('');\n const [count, setCount] = useState(0);\n\n // Expose the composer's focus to Thread.Root so the header caret can focus it.\n useEffect(() => {\n registerComposerFocus(() => composerRef.current?.focus());\n return () => registerComposerFocus(undefined);\n }, [registerComposerFocus]);\n\n const editorExtensions = useMemo(\n () =>\n [\n createBasicExtensions({ placeholder: placeholder ?? t('message.placeholder') }),\n createThemeExtensions({ themeMode }),\n listener({ onChange: ({ text }) => (messageRef.current = text) }),\n command,\n extensions,\n ].filter(Boolean) as Extension[],\n [themeMode, placeholder, t, extensions, count],\n );\n\n const handleSend = useCallback(() => {\n const text = messageRef.current;\n if (!text?.length || !onSend) {\n return;\n }\n if (onSend(text)) {\n messageRef.current = '';\n setCount((value) => value + 1);\n }\n }, []);\n\n return (\n <Message.Textbox\n ref={composerRef}\n {...metadata}\n autoFocus={autoFocus}\n disabled={disabled}\n extensions={editorExtensions}\n onSend={handleSend}\n />\n );\n};\n\nThreadTextbox.displayName = 'Thread.Textbox';\n\n//\n// Status\n//\n\nexport type ThreadStatusProps = ThemedClassName<PropsWithChildren> & {\n activity?: boolean;\n};\n\nconst ThreadStatus = forwardRef<HTMLDivElement, ThreadStatusProps>(\n ({ activity, classNames, children, ...props }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n return (\n <div\n {...props}\n className={mx(\n 'col-start-2 grid grid-cols-[min-content_1fr_max-content] pb-2 pe-2 text-xs text-description',\n classNames,\n )}\n ref={forwardedRef}\n >\n <Icon\n icon='ph--spinner--bold'\n classNames='w-6 h-4 invisible data-[visible=show]:visible animate-spin-slow'\n data-visible={activity ? 'show' : 'hide'}\n />\n <span className='truncate min-w-0' aria-live='polite'>\n {activity ? children : null}\n </span>\n <span className={mx('text-end', hoverableControlItem)}>{t('enter-to-send.message')}</span>\n </div>\n );\n },\n);\n\nThreadStatus.displayName = 'Thread.Status';\n\n//\n// Thread\n//\n\nexport const Thread = {\n Root: ThreadRoot,\n Content: ThreadContent,\n Header: ThreadHeader,\n Messages: ThreadMessages,\n Textbox: ThreadTextbox,\n Status: ThreadStatus,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/command.ts","../../src/context.ts","../../src/Message/Message.tsx","../../src/Thread/Thread.tsx"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { HighlightStyle, StreamLanguage, syntaxHighlighting } from '@codemirror/language';\nimport { type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\n\nimport { tags } from '@dxos/ui-editor';\nimport { mx } from '@dxos/ui-theme';\n\n/**\n * Highlights leading slash-commands (e.g. `/resolve`) and `@mention` tags\n * (e.g. `@Kai`, anywhere) in the message composer.\n * https://github.com/codemirror/stream-parser/blob/main/test/test-stream-parser.ts\n */\nconst parser = StreamLanguage.define<{ count: number }>({\n startState: () => ({ count: 0 }),\n token: (stream, state) => {\n state.count++;\n if (stream.eatSpace()) {\n return null;\n }\n // Leading slash-command (first token only).\n if (state.count === 1 && stream.match(/^\\/\\w+/)) {\n return 'tagName';\n }\n // @mention (anywhere).\n if (stream.match(/^@\\w+/)) {\n return 'labelName';\n }\n stream.next();\n return null;\n },\n});\n\nconst styles = HighlightStyle.define([\n {\n tag: tags.tagName,\n class: mx('dx-tag dx-tag--indigo'),\n },\n {\n tag: tags.labelName,\n class: mx('dx-tag dx-tag--blue'),\n },\n]);\n\n// Center the inline `.dx-tag` pills on the text line. `.dx-tag` is `inline-block`\n// with vertical padding, so on a CodeMirror line it baseline-aligns and rides\n// high; overriding `vertical-align` recentres it (cf. the `cm-reference-pill`\n// precedent in `@dxos/react-ui-chat`).\nconst theme = EditorView.theme({\n '.dx-tag': {\n verticalAlign: 'bottom',\n },\n});\n\nexport const command: Extension = [parser, syntaxHighlighting(styles), theme];\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { createContext } from '@radix-ui/react-context';\nimport { type FC, type ReactNode } from 'react';\n\n// Imported so TypeScript can name this type in the emitted .d.ts (ThreadContext → Message).\n// eslint-disable-next-line unused-imports/no-unused-imports\nimport { type Message } from '@dxos/types';\n\nimport { type ThreadContextValue } from './types';\n\n/**\n * Context provided by `Thread.Root` and consumed by its parts. Extends the\n * consumer-facing {@link ThreadContextValue} with internal coordination (e.g.\n * focusing the composer from the header's select affordance).\n */\nexport type ThreadContext = ThreadContextValue & {\n /** Register the composer's focus handler (set by `Thread.Textbox`). */\n registerComposerFocus: (focus: (() => void) | undefined) => void;\n /** Focus the thread composer (used by `Thread.Header`'s select affordance). */\n focusComposer: () => void;\n};\n\nexport const [ThreadContextProvider, useThreadContext]: readonly [\n FC<ThreadContext & { children: ReactNode }>,\n (consumerName: string) => ThreadContext,\n] = createContext<ThreadContext>('Thread');\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { EditorView } from '@codemirror/view';\nimport { format } from 'date-fns/format';\nimport React, {\n type ComponentPropsWithoutRef,\n type ComponentPropsWithRef,\n type ReactNode,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\n\nimport { Obj, Ref } from '@dxos/echo';\nimport {\n Avatar,\n IconButton,\n type ThemedClassName,\n useOnTransition,\n useThemeContext,\n useTranslation,\n} from '@dxos/react-ui';\nimport { type UseTextEditorProps, useTextEditor } from '@dxos/react-ui-editor';\nimport { type ContentBlock, type Message as MessageType } from '@dxos/types';\nimport { createBasicExtensions, createThemeExtensions, keymap, listener } from '@dxos/ui-editor';\nimport { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx } from '@dxos/ui-theme';\nimport { hexToEmoji, hexToHue, isTruthy } from '@dxos/util';\n\nimport { translationKey } from '#translations';\n\nimport { command } from '../command';\nimport { useThreadContext } from '../context';\nimport { type MessageMetadata } from '../types';\n\nconst avatarSize = 7;\n\nconst buttonGroupClassNames = 'flex flex-row items-center gap-0.5 pe-2';\nconst buttonClassNames = 'p-1! transition-opacity';\n\n//\n// Root\n//\n\nexport type MessageRootProps = ThemedClassName<\n ComponentPropsWithRef<'div'> & MessageMetadata & Partial<{ continues: boolean; controls: ReactNode }>\n>;\n\n// TODO(burdon): Show authorName on tooltip.\nconst MessageRoot = forwardRef<HTMLDivElement, MessageRootProps>(\n (\n {\n authorImgSrc,\n authorId,\n authorName,\n authorAvatarProps,\n continues = true,\n controls,\n children,\n classNames,\n ...rootProps\n },\n forwardedRef,\n ) => {\n // Must wrap the message since Avatar.Label may be used in the content.\n // Columns mirror Thread.Header (avatar/rail · content · controls) so trailing\n // controls align with the thread header's controls.\n return (\n <Avatar.Root>\n <div\n data-testid='thread.message'\n {...rootProps}\n className={mx('grid grid-cols-[var(--dx-rail-size)_1fr_min-content] w-full', classNames)}\n ref={forwardedRef}\n >\n <div className='flex flex-col items-center gap-2 pt-1'>\n <Avatar.Content\n size={avatarSize}\n hue={authorAvatarProps?.hue || hexToHue(authorId ?? '0')}\n fallback={authorAvatarProps?.emoji || hexToEmoji(authorId ?? '0')}\n {...(authorImgSrc && { imgSrc: authorImgSrc })}\n />\n {continues && <div className='w-px grow bg-separator' />}\n </div>\n <div className='py-1 min-w-0'>{children}</div>\n {controls && <div className='self-start'>{controls}</div>}\n </div>\n </Avatar.Root>\n );\n },\n);\n\nMessageRoot.displayName = 'Message.Root';\n\n//\n// Heading\n//\n\nexport type MessageHeadingProps = ThemedClassName<ComponentPropsWithoutRef<'div'>> &\n Pick<MessageMetadata, 'authorName' | 'timestamp'>;\n\nconst MessageHeading = ({ children, classNames, timestamp, authorName, ...props }: MessageHeadingProps) => {\n return (\n <div {...props} className={mx('flex gap-2 items-start', classNames)}>\n <p className='grow flex items-baseline gap-2 min-w-0'>\n <MessageAuthorName authorName={authorName} />\n {timestamp && <MessageTime timestamp={timestamp} />}\n </p>\n {children}\n </div>\n );\n};\n\nMessageHeading.displayName = 'Message.Heading';\n\nexport type MessageAuthorNameProps = Pick<MessageMetadata, 'authorName'>;\n\nconst MessageAuthorName = ({ authorName }: MessageAuthorNameProps) => {\n const { t } = useTranslation(translationKey);\n return (\n <Avatar.Label classNames='block truncate min-w-0 shrink text-sm text-subdued'>\n {authorName ?? t('anonymous.label')}\n </Avatar.Label>\n );\n};\n\nMessageAuthorName.displayName = 'Message.AuthorName';\n\nexport type MessageTimeProps = Pick<MessageMetadata, 'timestamp'>;\n\nconst MessageTime = ({ timestamp }: MessageTimeProps) => {\n const { dtLocale } = useTranslation(translationKey);\n const dt = timestamp ? new Date(timestamp) : undefined;\n return (\n <time className='shrink-0 text-subdued text-xs' dateTime={dt?.toISOString()}>\n {dt ? format(dt, 'p', { locale: dtLocale }) : ''}\n </time>\n );\n};\n\nMessageTime.displayName = 'Message.Time';\n\n//\n// Body\n//\n\nexport type MessageBodyProps = {\n /** The message whose content blocks are rendered. */\n message: MessageType.Message;\n /** When true, the local user authored this message. */\n isAuthor?: boolean;\n /** When true, the text block is editable. */\n editing?: boolean;\n /** Persist an edited text block. */\n onSave?: (text: string) => void;\n};\n\n/**\n * Renders a message's content blocks: text (via editor), proposal, and\n * object/reference tiles (delegated to the injected `Object` component).\n */\nconst MessageBody = ({ message, isAuthor, editing, onSave }: MessageBodyProps) => {\n const { components } = useThreadContext('Message.Body');\n const textBlockIndex = message.blocks.findIndex((block) => block._tag === 'text');\n const textBlock = textBlockIndex !== -1 ? (message.blocks[textBlockIndex] as ContentBlock.Text) : undefined;\n const proposalBlock = message.blocks.find((block) => block._tag === 'proposal') as ContentBlock.Proposal | undefined;\n const changeBlock = message.blocks.find((block) => block._tag === 'change') as ContentBlock.Change | undefined;\n const references = message.blocks\n .filter((block) => block._tag === 'reference')\n .map((block) => (block as ContentBlock.Reference).reference);\n const Object = components.Object;\n\n return (\n <>\n {textBlock && <TextBlock block={textBlock} isAuthor={isAuthor} editing={editing} onSave={onSave} />}\n {proposalBlock && <div className='me-4 italic'>{proposalBlock.text}</div>}\n {changeBlock && (\n <p className='me-4 text-sm break-words'>\n {changeBlock.before && <span className='line-through opacity-60'>{changeBlock.before}</span>}\n {changeBlock.before && changeBlock.after && ' '}\n {changeBlock.after && <span>{changeBlock.after}</span>}\n </p>\n )}\n {Object &&\n Ref.Array.targets(references).map((reference, index) => (\n <Object key={index} subject={reference as Obj.Unknown} />\n ))}\n </>\n );\n};\n\nMessageBody.displayName = 'Message.Body';\n\nconst TextBlock = ({\n block,\n isAuthor,\n editing,\n onSave,\n}: {\n block: ContentBlock.Text;\n isAuthor?: boolean;\n editing?: boolean;\n onSave?: (text: string) => void;\n}) => {\n const { themeMode } = useThemeContext();\n const inMemoryContentRef = useRef(block.text);\n\n const handleDocumentChange = useCallback((next: string) => {\n inMemoryContentRef.current = next;\n }, []);\n\n const saveDocumentChange = useCallback(() => {\n onSave?.(inMemoryContentRef.current);\n }, [onSave]);\n\n useOnTransition(editing, true, false, saveDocumentChange);\n\n const { parentRef, focusAttributes, view } = useTextEditor(\n () => ({\n initialValue: block.text,\n extensions: [\n // Edit mode is authorisation enough — the control that gets here is already gated on\n // `isAuthor` — and a mid-edit flip to read-only makes the editor drop input silently.\n createBasicExtensions({ readOnly: !editing }),\n createThemeExtensions({ themeMode }),\n command,\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n handleDocumentChange(update.state.doc.toString());\n }\n }),\n ],\n }),\n // While editing, the editor owns its content and its authorisation: pinning both keeps an incoming\n // `block.text` update or member-list refresh from rebuilding the view being typed in. `editing` is\n // itself a dep, so the flip still rebuilds.\n [editing, editing ? undefined : block.text, editing ? undefined : isAuthor, themeMode, handleDocumentChange],\n );\n\n useEffect(() => {\n if (editing) {\n view?.focus();\n }\n }, [editing, view]);\n\n return <div ref={parentRef} className='me-4' {...focusAttributes} />;\n};\n\n//\n// Textbox\n//\n\nexport type MessageTextboxProps = {\n disabled?: boolean;\n onSend?: () => void;\n onClear?: () => void;\n onEditorFocus?: () => void;\n} & MessageMetadata &\n UseTextEditorProps;\n\nconst keyBindings = ({ onSend, onClear }: Pick<MessageTextboxProps, 'onSend' | 'onClear'>) => [\n {\n key: 'Enter',\n run: () => {\n if (onSend) {\n onSend();\n return true;\n }\n return false;\n },\n },\n {\n key: 'Meta+Backspace',\n run: () => {\n if (onClear) {\n onClear();\n return true;\n }\n return false;\n },\n },\n];\n\nexport type MessageTextboxHandle = { focus: () => void };\n\nconst MessageTextbox = forwardRef<MessageTextboxHandle, MessageTextboxProps>(\n (\n {\n id,\n authorId,\n authorName,\n authorImgSrc,\n authorAvatarProps,\n disabled,\n extensions,\n onSend,\n onClear,\n onEditorFocus,\n ...editorProps\n },\n forwardedRef,\n ) => {\n const { parentRef, focusAttributes, view } = useTextEditor(\n () => ({\n id,\n extensions: [\n keymap.of(keyBindings({ onSend, onClear })),\n listener({\n onFocus: ({ focusing }) => {\n if (focusing) {\n onEditorFocus?.();\n }\n },\n }),\n extensions,\n ].filter(isTruthy),\n ...editorProps,\n }),\n [id, extensions],\n );\n\n useImperativeHandle(forwardedRef, () => ({ focus: () => view?.focus() }), [view]);\n\n return (\n <MessageRoot {...{ id, authorId, authorName, authorImgSrc, authorAvatarProps }} continues={false}>\n {/*\n Addressable: the reply composer is the only textbox in a thread that is not a message body,\n so without a testid a test can only guess at it by editor order.\n */}\n <div\n ref={parentRef}\n data-testid='thread.reply'\n className={mx('py-0.5 me-1 rounded-xs dx-focus-ring', disabled && 'opacity-50')}\n {...focusAttributes}\n />\n </MessageRoot>\n );\n },\n);\n\nMessageTextbox.displayName = 'Message.Textbox';\n\n//\n// Tile\n//\n\nexport type MessageTileProps = {\n message: MessageType.Message;\n classNames?: MessageRootProps['classNames'];\n /** Whether the avatar-rail continuation line is drawn below the tile; false for the last tile. */\n continues?: boolean;\n};\n\n/**\n * Full message tile (frame + heading + controls + body). Reads `Thread.Root`\n * context for metadata resolution, injected renderers, and callbacks. This is\n * the unit rendered by `Thread.Messages`.\n */\nconst MessageTile = ({ message, classNames, continues = true }: MessageTileProps) => {\n const { t } = useTranslation(translationKey);\n const {\n getMetadata,\n identityDid,\n editable,\n onMessageDelete,\n onAcceptProposal,\n onAcceptChange,\n onRejectChange,\n onMessageSelect,\n currentMessageId,\n } = useThreadContext('Message.Tile');\n const [editing, setEditing] = useState(false);\n\n const metadata = getMetadata(message);\n const isAuthor = !!identityDid && identityDid === metadata.authorId;\n const hasProposal = message.blocks.some((block) => block._tag === 'proposal');\n const hasChange = message.blocks.some((block) => block._tag === 'change');\n\n const handleEdit = useCallback(() => setEditing((value) => !value), []);\n const handleDelete = useCallback(() => onMessageDelete?.(message.id), [onMessageDelete, message.id]);\n const handleAcceptProposal = useCallback(() => onAcceptProposal?.(message.id), [onAcceptProposal, message.id]);\n const handleAcceptChange = useCallback(() => onAcceptChange?.(message.id), [onAcceptChange, message.id]);\n const handleRejectChange = useCallback(() => onRejectChange?.(message.id), [onRejectChange, message.id]);\n const handleSelect = useCallback(() => onMessageSelect?.(message.id), [onMessageSelect, message.id]);\n const handleSave = useCallback(\n (text: string) => {\n Obj.update(message, (message) => {\n const block = message.blocks.find((block) => block._tag === 'text');\n if (block && block._tag === 'text') {\n block.text = text;\n }\n });\n },\n [message],\n );\n\n const showEdit = isAuthor && editable;\n const showAccept = hasProposal && !!onAcceptProposal;\n const showAcceptChange = hasChange && !!onAcceptChange;\n const showRejectChange = hasChange && !!onRejectChange;\n const showDelete = !!onMessageDelete;\n const controls =\n showEdit || showAccept || showAcceptChange || showRejectChange || showDelete ? (\n <div className={buttonGroupClassNames}>\n {showEdit && (\n <IconButton\n data-testid={editing ? 'thread.message.save' : 'thread.message.edit'}\n variant='ghost'\n icon={editing ? 'ph--check--regular' : 'ph--pencil-simple--regular'}\n iconOnly\n label={t(editing ? 'save-message.label' : 'edit-message.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleEdit}\n />\n )}\n {showAccept && (\n <IconButton\n data-testid='thread.message.accept'\n variant='ghost'\n icon='ph--check--regular'\n iconOnly\n label={t('accept-proposal.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleAcceptProposal}\n />\n )}\n {showAcceptChange && (\n <IconButton\n data-testid='thread.message.accept-change'\n variant='ghost'\n icon='ph--check--regular'\n iconOnly\n label={t('accept-change.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleAcceptChange}\n />\n )}\n {showRejectChange && (\n <IconButton\n data-testid='thread.message.reject-change'\n variant='ghost'\n icon='ph--x--regular'\n iconOnly\n label={t('reject-change.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleRejectChange}\n />\n )}\n {showDelete && (\n <IconButton\n data-testid='thread.message.delete'\n variant='ghost'\n icon='ph--x--regular'\n iconOnly\n label={t('delete-message.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleDelete}\n />\n )}\n </div>\n ) : undefined;\n\n return (\n <MessageRoot\n {...metadata}\n continues={continues}\n controls={controls}\n // Selecting a tile is how the host reveals what it refers to (a suggestion's range in the\n // document), so the whole tile is the target — the accent marks which one is showing.\n onClick={onMessageSelect ? handleSelect : undefined}\n aria-current={currentMessageId === message.id ? 'location' : undefined}\n classNames={[\n hoverableControls,\n hoverableFocusedWithinControls,\n onMessageSelect && 'cursor-pointer',\n currentMessageId === message.id && 'bg-current-surface',\n classNames,\n ]}\n >\n <MessageHeading authorName={metadata.authorName} timestamp={metadata.timestamp} />\n <MessageBody message={message} isAuthor={isAuthor} editing={editing} onSave={handleSave} />\n </MessageRoot>\n );\n};\n\nMessageTile.displayName = 'Message.Tile';\n\n//\n// Group\n//\n\nexport type MessageGroupProps = {\n /** Consecutive same-sender messages, in ascending time order, rendered as one tile. */\n messages: readonly MessageType.Message[];\n /** Whether the avatar-rail continuation line is drawn below the tile; false for the last tile. */\n continues?: boolean;\n classNames?: MessageRootProps['classNames'];\n};\n\n/**\n * Groups consecutive same-sender messages (see `Thread.Messages`'s grouping\n * window) into a single tile: one heading (author + first message's\n * timestamp) followed by one body per message, stacked in order. Per-message\n * edit/delete controls are not shown per-row in a group — v1 shows them for\n * the group's first message only, since the heading/controls layout is keyed\n * to a single message.\n */\nconst MessageGroup = ({ messages, continues = true, classNames }: MessageGroupProps) => {\n const { t } = useTranslation(translationKey);\n const { getMetadata, identityDid, editable, onMessageDelete, onAcceptProposal } = useThreadContext('Message.Group');\n const [editing, setEditing] = useState(false);\n\n const first = messages[0];\n const metadata = getMetadata(first);\n const isAuthor = !!identityDid && identityDid === metadata.authorId;\n const hasProposal = first.blocks.some((block) => block._tag === 'proposal');\n\n const handleEdit = useCallback(() => setEditing((value) => !value), []);\n const handleDelete = useCallback(() => onMessageDelete?.(first.id), [onMessageDelete, first.id]);\n const handleAcceptProposal = useCallback(() => onAcceptProposal?.(first.id), [onAcceptProposal, first.id]);\n const handleSave = useCallback(\n (text: string) => {\n Obj.update(first, (first) => {\n const block = first.blocks.find((block) => block._tag === 'text');\n if (block && block._tag === 'text') {\n block.text = text;\n }\n });\n },\n [first],\n );\n\n const showEdit = isAuthor && editable;\n const showAccept = hasProposal && !!onAcceptProposal;\n const showDelete = !!onMessageDelete;\n const controls =\n showEdit || showAccept || showDelete ? (\n <div className={buttonGroupClassNames}>\n {showEdit && (\n <IconButton\n data-testid={editing ? 'thread.message.save' : 'thread.message.edit'}\n variant='ghost'\n icon={editing ? 'ph--check--regular' : 'ph--pencil-simple--regular'}\n iconOnly\n label={t(editing ? 'save-message.label' : 'edit-message.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleEdit}\n />\n )}\n {showAccept && (\n <IconButton\n data-testid='thread.message.accept'\n variant='ghost'\n icon='ph--check--regular'\n iconOnly\n label={t('accept-proposal.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleAcceptProposal}\n />\n )}\n {showDelete && (\n <IconButton\n data-testid='thread.message.delete'\n variant='ghost'\n icon='ph--x--regular'\n iconOnly\n label={t('delete-message.label')}\n classNames={[buttonClassNames, hoverableControlItem]}\n onClick={handleDelete}\n />\n )}\n </div>\n ) : undefined;\n\n return (\n <MessageRoot\n {...metadata}\n continues={continues}\n controls={controls}\n classNames={[hoverableControls, hoverableFocusedWithinControls, classNames]}\n >\n <MessageHeading authorName={metadata.authorName} timestamp={metadata.timestamp} />\n {messages.map((message) => (\n <MessageBody\n key={message.id}\n message={message}\n isAuthor={isAuthor}\n editing={editing && message === first}\n onSave={handleSave}\n />\n ))}\n </MessageRoot>\n );\n};\n\nMessageGroup.displayName = 'Message.Group';\n\n//\n// Message\n//\n\nexport const Message = {\n Root: MessageRoot,\n Heading: MessageHeading,\n AuthorName: MessageAuthorName,\n Time: MessageTime,\n Body: MessageBody,\n Textbox: MessageTextbox,\n Tile: MessageTile,\n Group: MessageGroup,\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { format } from 'date-fns/format';\nimport { type Locale } from 'date-fns/locale';\nimport { startOfDay } from 'date-fns/startOfDay';\nimport React, {\n type ComponentPropsWithRef,\n type PropsWithChildren,\n type ReactNode,\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { Obj } from '@dxos/echo';\nimport {\n type ComposableProps,\n Icon,\n IconButton,\n ScrollArea,\n type ThemedClassName,\n composable,\n composableProps,\n useThemeContext,\n useTranslation,\n} from '@dxos/react-ui';\nimport { type DndContainerHandler } from '@dxos/react-ui-dnd';\nimport { Mosaic, type MosaicTileProps } from '@dxos/react-ui-mosaic';\nimport { type Message as MessageType } from '@dxos/types';\nimport { type Extension, createBasicExtensions, createThemeExtensions, listener } from '@dxos/ui-editor';\nimport { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx } from '@dxos/ui-theme';\n\nimport { translationKey } from '#translations';\n\nimport { command } from '../command';\nimport { ThreadContextProvider, useThreadContext } from '../context';\nimport { Message } from '../Message';\nimport { type MessageMetadata, type ThreadContextValue } from '../types';\n\nconst getMessageId = (message: MessageType.Message) => Obj.getURI(message);\n\n//\n// Root\n//\n\nexport type ThreadRootProps = PropsWithChildren<\n Omit<ThreadContextValue, 'components'> & Partial<Pick<ThreadContextValue, 'components'>>\n>;\n\n/**\n * Headless root of a thread. Provides message-tile context (metadata resolver,\n * injected renderers, callbacks). Requires an ambient `Dnd.Root` ancestor,\n * within which `Thread.Messages` renders its virtual stack. Renders no DOM of\n * its own — wrap the visible thread chrome in `Thread.Content`.\n */\nconst ThreadRoot = ({\n children,\n getMetadata,\n components,\n identityDid,\n editable,\n onMessageDelete,\n onAcceptProposal,\n onAcceptChange,\n onRejectChange,\n onMessageSelect,\n currentMessageId,\n}: ThreadRootProps) => {\n // Composer focus handler registered by Thread.Textbox; invoked by Thread.Header's caret.\n const composerFocus = useRef<(() => void) | undefined>(undefined);\n\n const registerComposerFocus = useCallback((focus: (() => void) | undefined) => {\n composerFocus.current = focus;\n }, []);\n\n const focusComposer = useCallback(() => composerFocus.current?.(), []);\n\n return (\n <ThreadContextProvider\n getMetadata={getMetadata}\n components={components ?? {}}\n identityDid={identityDid}\n editable={editable}\n registerComposerFocus={registerComposerFocus}\n focusComposer={focusComposer}\n onMessageDelete={onMessageDelete}\n onAcceptProposal={onAcceptProposal}\n onAcceptChange={onAcceptChange}\n onRejectChange={onRejectChange}\n onMessageSelect={onMessageSelect}\n currentMessageId={currentMessageId}\n >\n {children}\n </ThreadContextProvider>\n );\n};\n\nThreadRoot.displayName = 'Thread.Root';\n\n//\n// Content\n//\n\ntype ThreadContentExtra = {\n id?: string;\n current?: boolean | string;\n} & Pick<ComponentPropsWithRef<'div'>, 'onClickCapture' | 'onFocusCapture'>;\n\nexport type ThreadContentProps = ComposableProps<ThreadContentExtra>;\n\n/** Visible thread container (the attention surface that hosts header / messages / composer). */\nconst ThreadContent = composable<HTMLDivElement, ThreadContentExtra>(\n ({ children, current, id, ...props }, forwardedRef) => {\n return (\n <div\n {...composableProps(props, {\n role: 'group',\n classNames: [\n 'flex flex-col bg-[var(--surface-bg)] current-related dx-attention-surface [--controls-opacity:0]',\n hoverableFocusedWithinControls,\n ],\n })}\n data-testid='thread'\n id={id}\n aria-current={current ? 'location' : undefined}\n ref={forwardedRef}\n >\n {children}\n </div>\n );\n },\n);\n\nThreadContent.displayName = 'Thread.Content';\n\n//\n// Header\n//\n\nexport type ThreadHeaderProps = Omit<\n ComposableProps<{\n /** Snippet text rendered inside a `<p>` (a string, not a DOM element). */\n title?: string;\n detached?: boolean;\n /** Whether this is the current/selected thread; accents the title. */\n current?: boolean;\n /** Trailing controls rendered in the right column (aligns with message-tile controls). */\n controls?: ReactNode;\n /** Invoked when the caret affordance is activated to select/focus this thread. */\n onSelect?: () => void;\n }>,\n 'children'\n>;\n\n/**\n * Thread header row: caret (rail) · snippet (content) · controls. Owns its own\n * `[rail · 1fr · controls]` grid so the trailing controls align with message-tile\n * controls (which use the same template) — no grid is leaked in from the caller.\n */\nconst ThreadHeader = composable<HTMLDivElement, ThreadHeaderProps>(\n ({ title, detached, current, controls, onSelect, ...props }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n const { focusComposer } = useThreadContext('Thread.Header');\n const handleSelect = useCallback(() => {\n onSelect?.();\n focusComposer();\n }, [onSelect, focusComposer]);\n\n return (\n <div\n {...composableProps(props, {\n classNames: [\n 'grid grid-cols-[var(--dx-rail-size)_1fr_min-content] items-center',\n hoverableControls,\n hoverableFocusedWithinControls,\n ],\n })}\n ref={forwardedRef}\n >\n <div className='flex items-center justify-center'>\n <IconButton\n iconOnly\n variant='ghost'\n density='sm'\n icon='ph--caret-double-right--regular'\n label={t('select-thread.label')}\n classNames='text-description'\n onClick={handleSelect}\n />\n </div>\n <div className='flex items-center overflow-hidden'>\n <p\n role='heading'\n data-testid='thread.heading'\n className={mx(\n 'me-2 font-medium truncate italic',\n current ? 'text-accent-text' : 'text-description',\n detached && 'line-through decoration-1',\n )}\n >\n {title}\n </p>\n </div>\n {controls}\n </div>\n );\n },\n);\n\nThreadHeader.displayName = 'Thread.Header';\n\n//\n// Messages\n//\n\n/** A run of consecutive same-sender messages (within the grouping window) rendered as one tile. */\ntype MessageGroupItem = { kind: 'group'; id: string; messages: MessageType.Message[]; last?: boolean };\n\n/**\n * A divider row between groups: day-labeled (calendar-day boundary) or plain\n * (a same-day gap exceeding `gapDividerMs`). Day boundaries take priority\n * when both coincide on the same message — see `groupMessages`.\n */\ntype DividerItem = { kind: 'divider'; id: string; label?: string };\n\ntype ThreadItem = MessageGroupItem | DividerItem;\n\nconst getThreadItemId = (item: ThreadItem) => item.id;\n\n/** Stable per-sender key: prefers the DID, then the (deprecated) identity key, then name/email, else 'anon'. */\nconst senderKey = (message: MessageType.Message): string =>\n message.sender.identityDid ?? message.sender.identityKey ?? message.sender.name ?? message.sender.email ?? 'anon';\n\n/** Message send time in epoch ms; malformed/missing `created` sorts as if sent at the epoch. */\nconst messageTime = (message: MessageType.Message): number => {\n const time = Date.parse(message.created);\n return Number.isFinite(time) ? time : 0;\n};\n\n/**\n * Preprocesses ascending, time-ordered `messages` into a flat list of divider\n * and group items for `Thread.Messages`'s virtual stack:\n * - A day divider (labeled with the calendar date) precedes the first message\n * of each calendar day.\n * - A plain divider (no label) marks a same-day gap exceeding `gapDividerMs`.\n * - When both would fall on the same message, only the day divider is emitted.\n * - Consecutive messages from the same sender within `groupWindowMs` of the\n * previous message in the group are merged into one `MessageGroupItem`; a\n * divider always starts a new group.\n */\nconst groupMessages = (\n messages: readonly MessageType.Message[],\n {\n groupWindowMs,\n dayDivider,\n gapDividerMs,\n dtLocale,\n }: { groupWindowMs: number; dayDivider: boolean; gapDividerMs: number; dtLocale?: Locale },\n): ThreadItem[] => {\n const items: ThreadItem[] = [];\n let currentGroup: MessageGroupItem | undefined;\n // Tracks the last message appended to `currentGroup`, since `Array.prototype.at(-1)`\n // on `currentGroup.messages` would need a non-null assertion despite `currentGroup`\n // always being non-empty by construction.\n let lastGroupMessage: MessageType.Message | undefined;\n let prevTime: number | undefined;\n let prevDay: number | undefined;\n\n for (const message of messages) {\n const time = messageTime(message);\n const day = startOfDay(time).getTime();\n\n const dayBoundary = dayDivider && (prevDay === undefined || day !== prevDay);\n const gapBoundary = !dayBoundary && prevTime !== undefined && time - prevTime > gapDividerMs;\n\n if (dayBoundary) {\n items.push({\n kind: 'divider',\n id: `divider:day:${day}`,\n label: format(day, 'EEEE, MMMM d', { locale: dtLocale }),\n });\n currentGroup = undefined;\n } else if (gapBoundary) {\n items.push({ kind: 'divider', id: `divider:gap:${time}` });\n currentGroup = undefined;\n }\n\n const sameSenderAsGroup = currentGroup && lastGroupMessage && senderKey(lastGroupMessage) === senderKey(message);\n const withinGroupWindow = currentGroup && lastGroupMessage && time - messageTime(lastGroupMessage) <= groupWindowMs;\n\n if (currentGroup && sameSenderAsGroup && withinGroupWindow) {\n currentGroup.messages.push(message);\n } else {\n currentGroup = { kind: 'group', id: getMessageId(message), messages: [message] };\n items.push(currentGroup);\n }\n lastGroupMessage = message;\n\n prevTime = time;\n prevDay = day;\n }\n\n // The trailing group is the last message tile; suppress its avatar-rail continuation line.\n if (currentGroup) {\n currentGroup.last = true;\n }\n\n return items;\n};\n\n//\n// Divider\n//\n\nconst ThreadDivider = ({ label }: { label?: string }) =>\n label ? (\n <div className='flex items-center gap-2 px-2 py-2 text-xs text-description'>\n <div className='h-px grow bg-separator' />\n <span className='shrink-0'>{label}</span>\n <div className='h-px grow bg-separator' />\n </div>\n ) : (\n <div className='px-2 py-2'>\n <div className='h-px bg-separator' />\n </div>\n );\n\nThreadDivider.displayName = 'Thread.Divider';\n\nconst ThreadItemAdapter = ({ id, data, location, draggable, current, selected }: MosaicTileProps<ThreadItem>) => (\n <Mosaic.Tile id={id} data={data} location={location} draggable={draggable} current={current} selected={selected}>\n {data.kind === 'divider' ? (\n <ThreadDivider label={data.label} />\n ) : (\n <Message.Group messages={data.messages} continues={!data.last} />\n )}\n </Mosaic.Tile>\n);\n\nexport type ThreadMessagesProps = ThemedClassName<{\n messages: readonly MessageType.Message[];\n /** Stable id of the owning thread; scopes the Mosaic container so multiple threads don't collide. */\n id?: string;\n /** Estimated tile height for the virtualizer. */\n estimateSize?: number;\n currentId?: string;\n /** Consecutive same-sender messages within this window (ms) are merged into one tile. */\n groupWindowMs?: number;\n /** Whether to insert a labeled divider before the first message of each calendar day. */\n dayDivider?: boolean;\n /** A same-day gap exceeding this (ms) inserts an unlabeled divider between groups. */\n gapDividerMs?: number;\n}>;\n\nconst DEFAULT_GROUP_WINDOW_MS = 60_000;\nconst DEFAULT_GAP_DIVIDER_MS = 3 * 60 * 60 * 1000;\n\n/** Virtualized stack of message tiles (via Mosaic), within an internal scroll area. */\nconst ThreadMessages = ({\n messages,\n id,\n estimateSize = 80,\n currentId,\n groupWindowMs = DEFAULT_GROUP_WINDOW_MS,\n dayDivider = true,\n gapDividerMs = DEFAULT_GAP_DIVIDER_MS,\n classNames,\n}: ThreadMessagesProps) => {\n const { dtLocale } = useTranslation(translationKey);\n const [viewport, setViewport] = useState<HTMLElement | null>(null);\n const items = useMemo(\n () => groupMessages(messages.filter(Boolean), { groupWindowMs, dayDivider, gapDividerMs, dtLocale }),\n [messages, groupWindowMs, dayDivider, gapDividerMs, dtLocale],\n );\n // Per-instance id keeps concurrent threads (incl. the same thread mounted twice) distinct in the DnD registry.\n const instanceId = useId();\n const eventHandler = useMemo<DndContainerHandler>(\n () => ({ id: `thread:${id ?? 'anon'}:${instanceId}`, canDrop: () => false }),\n [id, instanceId],\n );\n\n return (\n <Mosaic.Container\n asChild\n orientation='vertical'\n autoScroll={viewport}\n currentId={currentId}\n eventHandler={eventHandler}\n >\n <ScrollArea.Root classNames={mx('col-span-2 flex-1 min-h-0', classNames)} orientation='vertical'>\n <ScrollArea.Viewport ref={setViewport}>\n <Mosaic.VirtualStack\n Tile={ThreadItemAdapter}\n items={items}\n getId={getThreadItemId}\n draggable={false}\n getScrollElement={() => viewport}\n estimateSize={() => estimateSize}\n />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </Mosaic.Container>\n );\n};\n\nThreadMessages.displayName = 'Thread.Messages';\n\n//\n// Textbox\n//\n\nexport type ThreadTextboxProps = MessageMetadata & {\n placeholder?: string;\n autoFocus?: boolean;\n disabled?: boolean;\n extensions?: Extension;\n /**\n * Called with the composer content on send. Return `true` to accept (the\n * editor is cleared and remounted), `false` to reject.\n */\n onSend?: (text: string) => boolean;\n};\n\n/** Message composer pinned at the foot of a thread. */\nconst ThreadTextbox = ({ placeholder, autoFocus, disabled, extensions, onSend, ...metadata }: ThreadTextboxProps) => {\n const { t } = useTranslation(translationKey);\n const { themeMode } = useThemeContext();\n const { registerComposerFocus } = useThreadContext('Thread.Textbox');\n const composerRef = useRef<{ focus: () => void } | null>(null);\n const messageRef = useRef('');\n const [count, setCount] = useState(0);\n\n // Expose the composer's focus to Thread.Root so the header caret can focus it.\n useEffect(() => {\n registerComposerFocus(() => composerRef.current?.focus());\n return () => registerComposerFocus(undefined);\n }, [registerComposerFocus]);\n\n const editorExtensions = useMemo(\n () =>\n [\n createBasicExtensions({ placeholder: placeholder ?? t('message.placeholder') }),\n createThemeExtensions({ themeMode }),\n listener({ onChange: ({ text }) => (messageRef.current = text) }),\n command,\n extensions,\n ].filter(Boolean) as Extension[],\n [themeMode, placeholder, t, extensions, count],\n );\n\n const handleSend = useCallback(() => {\n const text = messageRef.current;\n if (!text?.length || !onSend) {\n return;\n }\n if (onSend(text)) {\n messageRef.current = '';\n setCount((value) => value + 1);\n }\n }, []);\n\n return (\n <Message.Textbox\n ref={composerRef}\n {...metadata}\n autoFocus={autoFocus}\n disabled={disabled}\n extensions={editorExtensions}\n onSend={handleSend}\n />\n );\n};\n\nThreadTextbox.displayName = 'Thread.Textbox';\n\n//\n// Status\n//\n\nexport type ThreadStatusProps = ThemedClassName<PropsWithChildren> & {\n activity?: boolean;\n};\n\nconst ThreadStatus = forwardRef<HTMLDivElement, ThreadStatusProps>(\n ({ activity, classNames, children, ...props }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n return (\n <div\n {...props}\n className={mx(\n 'col-start-2 grid grid-cols-[min-content_1fr_max-content] pb-2 pe-2 text-xs text-description',\n classNames,\n )}\n ref={forwardedRef}\n >\n <Icon\n icon='ph--spinner--bold'\n classNames='w-6 h-4 invisible data-[visible=show]:visible animate-spin-slow'\n data-visible={activity ? 'show' : 'hide'}\n />\n <span className='truncate min-w-0' aria-live='polite'>\n {activity ? children : null}\n </span>\n <span className={mx('text-end', hoverableControlItem)}>{t('enter-to-send.message')}</span>\n </div>\n );\n },\n);\n\nThreadStatus.displayName = 'Thread.Status';\n\n//\n// Thread\n//\n\nexport const Thread = {\n Root: ThreadRoot,\n Content: ThreadContent,\n Header: ThreadHeader,\n Messages: ThreadMessages,\n Textbox: ThreadTextbox,\n Status: ThreadStatus,\n};\n"],"mappings":"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"}
|
|
@@ -8,20 +8,20 @@ export type MessageRootProps = ThemedClassName<ComponentPropsWithRef<'div'> & Me
|
|
|
8
8
|
controls: ReactNode;
|
|
9
9
|
}>>;
|
|
10
10
|
export type MessageHeadingProps = ThemedClassName<ComponentPropsWithoutRef<'div'>> & Pick<MessageMetadata, 'authorName' | 'timestamp'>;
|
|
11
|
-
declare
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
11
|
+
declare const MessageHeading: {
|
|
12
|
+
({ children, classNames, timestamp, authorName, ...props }: MessageHeadingProps): React.JSX.Element;
|
|
13
|
+
displayName: string;
|
|
14
|
+
};
|
|
15
15
|
export type MessageAuthorNameProps = Pick<MessageMetadata, 'authorName'>;
|
|
16
|
-
declare
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
16
|
+
declare const MessageAuthorName: {
|
|
17
|
+
({ authorName }: MessageAuthorNameProps): React.JSX.Element;
|
|
18
|
+
displayName: string;
|
|
19
|
+
};
|
|
20
20
|
export type MessageTimeProps = Pick<MessageMetadata, 'timestamp'>;
|
|
21
|
-
declare
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
21
|
+
declare const MessageTime: {
|
|
22
|
+
({ timestamp }: MessageTimeProps): React.JSX.Element;
|
|
23
|
+
displayName: string;
|
|
24
|
+
};
|
|
25
25
|
export type MessageBodyProps = {
|
|
26
26
|
/** The message whose content blocks are rendered. */
|
|
27
27
|
message: MessageType.Message;
|
|
@@ -32,10 +32,14 @@ export type MessageBodyProps = {
|
|
|
32
32
|
/** Persist an edited text block. */
|
|
33
33
|
onSave?: (text: string) => void;
|
|
34
34
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Renders a message's content blocks: text (via editor), proposal, and
|
|
37
|
+
* object/reference tiles (delegated to the injected `Object` component).
|
|
38
|
+
*/
|
|
39
|
+
declare const MessageBody: {
|
|
40
|
+
({ message, isAuthor, editing, onSave }: MessageBodyProps): React.JSX.Element;
|
|
41
|
+
displayName: string;
|
|
42
|
+
};
|
|
39
43
|
export type MessageTextboxProps = {
|
|
40
44
|
disabled?: boolean;
|
|
41
45
|
onSend?: () => void;
|
|
@@ -51,10 +55,15 @@ export type MessageTileProps = {
|
|
|
51
55
|
/** Whether the avatar-rail continuation line is drawn below the tile; false for the last tile. */
|
|
52
56
|
continues?: boolean;
|
|
53
57
|
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Full message tile (frame + heading + controls + body). Reads `Thread.Root`
|
|
60
|
+
* context for metadata resolution, injected renderers, and callbacks. This is
|
|
61
|
+
* the unit rendered by `Thread.Messages`.
|
|
62
|
+
*/
|
|
63
|
+
declare const MessageTile: {
|
|
64
|
+
({ message, classNames, continues }: MessageTileProps): React.JSX.Element;
|
|
65
|
+
displayName: string;
|
|
66
|
+
};
|
|
58
67
|
export type MessageGroupProps = {
|
|
59
68
|
/** Consecutive same-sender messages, in ascending time order, rendered as one tile. */
|
|
60
69
|
messages: readonly MessageType.Message[];
|
|
@@ -62,28 +71,24 @@ export type MessageGroupProps = {
|
|
|
62
71
|
continues?: boolean;
|
|
63
72
|
classNames?: MessageRootProps['classNames'];
|
|
64
73
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Groups consecutive same-sender messages (see `Thread.Messages`'s grouping
|
|
76
|
+
* window) into a single tile: one heading (author + first message's
|
|
77
|
+
* timestamp) followed by one body per message, stacked in order. Per-message
|
|
78
|
+
* edit/delete controls are not shown per-row in a group — v1 shows them for
|
|
79
|
+
* the group's first message only, since the heading/controls layout is keyed
|
|
80
|
+
* to a single message.
|
|
81
|
+
*/
|
|
82
|
+
declare const MessageGroup: {
|
|
83
|
+
({ messages, continues, classNames }: MessageGroupProps): React.JSX.Element;
|
|
84
|
+
displayName: string;
|
|
85
|
+
};
|
|
69
86
|
export declare const Message: {
|
|
70
87
|
Root: React.ForwardRefExoticComponent<Omit<MessageRootProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
71
|
-
Heading:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
AuthorName: {
|
|
76
|
-
({ authorName }: MessageAuthorNameProps): React.JSX.Element;
|
|
77
|
-
displayName: string;
|
|
78
|
-
};
|
|
79
|
-
Time: {
|
|
80
|
-
({ timestamp }: MessageTimeProps): React.JSX.Element;
|
|
81
|
-
displayName: string;
|
|
82
|
-
};
|
|
83
|
-
Body: {
|
|
84
|
-
({ message, isAuthor, editing, onSave }: MessageBodyProps): React.JSX.Element;
|
|
85
|
-
displayName: string;
|
|
86
|
-
};
|
|
88
|
+
Heading: typeof MessageHeading;
|
|
89
|
+
AuthorName: typeof MessageAuthorName;
|
|
90
|
+
Time: typeof MessageTime;
|
|
91
|
+
Body: typeof MessageBody;
|
|
87
92
|
Textbox: React.ForwardRefExoticComponent<{
|
|
88
93
|
disabled?: boolean;
|
|
89
94
|
onSend?: () => void;
|
|
@@ -99,14 +104,8 @@ export declare const Message: {
|
|
|
99
104
|
selectionEnd?: boolean;
|
|
100
105
|
debug?: boolean;
|
|
101
106
|
} & React.RefAttributes<MessageTextboxHandle>>;
|
|
102
|
-
Tile:
|
|
103
|
-
|
|
104
|
-
displayName: string;
|
|
105
|
-
};
|
|
106
|
-
Group: {
|
|
107
|
-
({ messages, continues, classNames }: MessageGroupProps): React.JSX.Element;
|
|
108
|
-
displayName: string;
|
|
109
|
-
};
|
|
107
|
+
Tile: typeof MessageTile;
|
|
108
|
+
Group: typeof MessageGroup;
|
|
110
109
|
};
|
|
111
110
|
export {};
|
|
112
111
|
//# sourceMappingURL=Message.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../../../src/Message/Message.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EACZ,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAGf,OAAO,EAGL,KAAK,eAAe,EAIrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,kBAAkB,EAAiB,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAqB,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../../../src/Message/Message.tsx"],"names":[],"mappings":"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"}
|
|
@@ -3,9 +3,10 @@ import React from 'react';
|
|
|
3
3
|
type StoryArgs = {
|
|
4
4
|
editable: boolean;
|
|
5
5
|
};
|
|
6
|
+
declare const DefaultStory: ({ editable }: StoryArgs) => React.JSX.Element;
|
|
6
7
|
declare const meta: {
|
|
7
8
|
title: string;
|
|
8
|
-
render:
|
|
9
|
+
render: typeof DefaultStory;
|
|
9
10
|
decorators: import("@storybook/react").Decorator[];
|
|
10
11
|
parameters: {
|
|
11
12
|
layout: string;
|
|
@@ -22,7 +23,7 @@ declare const meta: {
|
|
|
22
23
|
readonly 'comment.placeholder': 'Enter comment...';
|
|
23
24
|
readonly 'settings-standalone.label': 'Enable standalone thread creation';
|
|
24
25
|
readonly 'anonymous.label': 'Anonymous';
|
|
25
|
-
readonly 'enter-to-send.message': 'Enter to add
|
|
26
|
+
readonly 'enter-to-send.message': 'Enter to add ⏎';
|
|
26
27
|
readonly 'edit-message.label': 'Edit';
|
|
27
28
|
readonly 'save-message.label': 'Save';
|
|
28
29
|
readonly 'delete-message.label': 'Delete';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Message.stories.d.ts","sourceRoot":"","sources":["../../../../src/Message/Message.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAkB,MAAM,OAAO,CAAC;AAavC,KAAK,SAAS,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"Message.stories.d.ts","sourceRoot":"","sources":["../../../../src/Message/Message.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAkB,MAAM,OAAO,CAAC;AAavC,KAAK,SAAS,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAIvC,QAAA,MAAM,YAAY,iBAAkB,SAAS,sBAY5C,CAAC;AAEF,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQ2B,CAAC;eAEvB,IAAI;AAEnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,QAAQ,EAAE,KAItB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAIzB,CAAC;AA+BF,eAAO,MAAM,UAAU,EAAE,KAkBxB,CAAC"}
|
|
@@ -4,10 +4,16 @@ import { type Message as MessageType } from '@dxos/types';
|
|
|
4
4
|
import { type Extension } from '@dxos/ui-editor';
|
|
5
5
|
import { type MessageMetadata, type ThreadContextValue } from '../types';
|
|
6
6
|
export type ThreadRootProps = PropsWithChildren<Omit<ThreadContextValue, 'components'> & Partial<Pick<ThreadContextValue, 'components'>>>;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Headless root of a thread. Provides message-tile context (metadata resolver,
|
|
9
|
+
* injected renderers, callbacks). Requires an ambient `Dnd.Root` ancestor,
|
|
10
|
+
* within which `Thread.Messages` renders its virtual stack. Renders no DOM of
|
|
11
|
+
* its own — wrap the visible thread chrome in `Thread.Content`.
|
|
12
|
+
*/
|
|
13
|
+
declare const ThreadRoot: {
|
|
14
|
+
({ children, getMetadata, components, identityDid, editable, onMessageDelete, onAcceptProposal, onAcceptChange, onRejectChange, onMessageSelect, currentMessageId, }: ThreadRootProps): React.JSX.Element;
|
|
15
|
+
displayName: string;
|
|
16
|
+
};
|
|
11
17
|
type ThreadContentExtra = {
|
|
12
18
|
id?: string;
|
|
13
19
|
current?: boolean | string;
|
|
@@ -24,12 +30,6 @@ export type ThreadHeaderProps = Omit<ComposableProps<{
|
|
|
24
30
|
/** Invoked when the caret affordance is activated to select/focus this thread. */
|
|
25
31
|
onSelect?: () => void;
|
|
26
32
|
}>, 'children'>;
|
|
27
|
-
declare function ThreadDivider({ label }: {
|
|
28
|
-
label?: string;
|
|
29
|
-
}): React.JSX.Element;
|
|
30
|
-
declare namespace ThreadDivider {
|
|
31
|
-
var displayName: string;
|
|
32
|
-
}
|
|
33
33
|
export type ThreadMessagesProps = ThemedClassName<{
|
|
34
34
|
messages: readonly MessageType.Message[];
|
|
35
35
|
/** Stable id of the owning thread; scopes the Mosaic container so multiple threads don't collide. */
|
|
@@ -44,10 +44,11 @@ export type ThreadMessagesProps = ThemedClassName<{
|
|
|
44
44
|
/** A same-day gap exceeding this (ms) inserts an unlabeled divider between groups. */
|
|
45
45
|
gapDividerMs?: number;
|
|
46
46
|
}>;
|
|
47
|
-
|
|
48
|
-
declare
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
/** Virtualized stack of message tiles (via Mosaic), within an internal scroll area. */
|
|
48
|
+
declare const ThreadMessages: {
|
|
49
|
+
({ messages, id, estimateSize, currentId, groupWindowMs, dayDivider, gapDividerMs, classNames, }: ThreadMessagesProps): React.JSX.Element;
|
|
50
|
+
displayName: string;
|
|
51
|
+
};
|
|
51
52
|
export type ThreadTextboxProps = MessageMetadata & {
|
|
52
53
|
placeholder?: string;
|
|
53
54
|
autoFocus?: boolean;
|
|
@@ -59,32 +60,24 @@ export type ThreadTextboxProps = MessageMetadata & {
|
|
|
59
60
|
*/
|
|
60
61
|
onSend?: (text: string) => boolean;
|
|
61
62
|
};
|
|
62
|
-
|
|
63
|
-
declare
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
/** Message composer pinned at the foot of a thread. */
|
|
64
|
+
declare const ThreadTextbox: {
|
|
65
|
+
({ placeholder, autoFocus, disabled, extensions, onSend, ...metadata }: ThreadTextboxProps): React.JSX.Element;
|
|
66
|
+
displayName: string;
|
|
67
|
+
};
|
|
66
68
|
export type ThreadStatusProps = ThemedClassName<PropsWithChildren> & {
|
|
67
69
|
activity?: boolean;
|
|
68
70
|
};
|
|
69
71
|
export declare const Thread: {
|
|
70
|
-
Root:
|
|
71
|
-
({ children, getMetadata, components, identityDid, editable, onMessageDelete, onAcceptProposal, onAcceptChange, onRejectChange, onMessageSelect, currentMessageId, }: ThreadRootProps): React.JSX.Element;
|
|
72
|
-
displayName: string;
|
|
73
|
-
};
|
|
72
|
+
Root: typeof ThreadRoot;
|
|
74
73
|
Content: React.ForwardRefExoticComponent<Omit<ThreadContentExtra, "className"> & {
|
|
75
74
|
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
76
75
|
} & Pick<React.HTMLAttributes<Element>, "children" | "role" | "style"> & React.RefAttributes<HTMLDivElement>>;
|
|
77
76
|
Header: React.ForwardRefExoticComponent<Omit<ThreadHeaderProps, "className"> & {
|
|
78
77
|
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
79
78
|
} & Pick<React.HTMLAttributes<Element>, "children" | "role" | "style"> & React.RefAttributes<HTMLDivElement>>;
|
|
80
|
-
Messages:
|
|
81
|
-
|
|
82
|
-
displayName: string;
|
|
83
|
-
};
|
|
84
|
-
Textbox: {
|
|
85
|
-
({ placeholder, autoFocus, disabled, extensions, onSend, ...metadata }: ThreadTextboxProps): React.JSX.Element;
|
|
86
|
-
displayName: string;
|
|
87
|
-
};
|
|
79
|
+
Messages: typeof ThreadMessages;
|
|
80
|
+
Textbox: typeof ThreadTextbox;
|
|
88
81
|
Status: React.ForwardRefExoticComponent<Omit<{
|
|
89
82
|
children?: ReactNode | undefined;
|
|
90
83
|
}, "className"> & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Thread.d.ts","sourceRoot":"","sources":["../../../../src/Thread/Thread.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,EACZ,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,SAAS,EAQf,MAAM,OAAO,CAAC;AAGf,OAAO,EACL,KAAK,eAAe,EAIpB,KAAK,eAAe,EAKrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,KAAK,SAAS,EAA0D,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"Thread.d.ts","sourceRoot":"","sources":["../../../../src/Thread/Thread.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,EACZ,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,SAAS,EAQf,MAAM,OAAO,CAAC;AAGf,OAAO,EACL,KAAK,eAAe,EAIpB,KAAK,eAAe,EAKrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,KAAK,SAAS,EAA0D,MAAM,iBAAiB,CAAC;AAQzG,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAQzE,MAAM,MAAM,eAAe,GAAG,iBAAiB,CAC7C,IAAI,CAAC,kBAAkB,EAAE,YAAY,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC,CACzF,CAAC;AAEF;;;;;GAKG;AACH,QAAA,MAAM,UAAU;0KAYb,eAAe;;CA4BjB,CAAC;AAQF,KAAK,kBAAkB,GAAG;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC5B,GAAG,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,CAAC,CAAC;AAE5E,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC,kBAAkB,CAAC,CAAC;AA+BrE,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,eAAe,CAAC;IACd,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC,EACF,UAAU,CACX,CAAC;AA2LF,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAAC;IAChD,QAAQ,EAAE,SAAS,WAAW,CAAC,OAAO,EAAE,CAAC;IACzC,qGAAqG;IACrG,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yFAAyF;IACzF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yFAAyF;IACzF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC,CAAC;AAKH,uFAAuF;AACvF,QAAA,MAAM,cAAc;sGASjB,mBAAmB;;CAoCrB,CAAC;AAQF,MAAM,MAAM,kBAAkB,GAAG,eAAe,GAAG;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACpC,CAAC;AAEF,uDAAuD;AACvD,QAAA,MAAM,aAAa;4EAA2E,kBAAkB;;CA+C/G,CAAC;AAQF,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC,iBAAiB,CAAC,GAAG;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAkCF,eAAO,MAAM,MAAM;IACjB,IAAI;IACJ,OAAO;;;IACP,MAAM;;;IACN,QAAQ;IACR,OAAO;IACP,MAAM;;;;;mBAzCK,OAAO;;CA0CnB,CAAC"}
|