@dxos/react-ui-thread 0.10.0 → 0.11.0
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 +738 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/translations.mjs +25 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/types/src/Message/Message.d.ts +19 -2
- package/dist/types/src/Message/Message.d.ts.map +1 -1
- package/dist/types/src/Message/Message.stories.d.ts +3 -0
- package/dist/types/src/Message/Message.stories.d.ts.map +1 -1
- package/dist/types/src/Message/index.d.ts +1 -1
- package/dist/types/src/Message/index.d.ts.map +1 -1
- package/dist/types/src/Thread/Thread.d.ts +20 -6
- package/dist/types/src/Thread/Thread.d.ts.map +1 -1
- package/dist/types/src/Thread/Thread.stories.d.ts +4 -0
- package/dist/types/src/Thread/Thread.stories.d.ts.map +1 -1
- package/dist/types/src/context.d.ts +1 -0
- package/dist/types/src/context.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +9 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +24 -24
- package/src/Message/Message.stories.tsx +52 -0
- package/src/Message/Message.tsx +181 -9
- package/src/Message/index.ts +1 -0
- package/src/Thread/Thread.stories.tsx +78 -1
- package/src/Thread/Thread.tsx +173 -19
- package/src/index.ts +1 -0
- package/src/translations.ts +2 -0
- package/src/types.ts +9 -1
- package/dist/lib/browser/chunk-QFRRLZVL.mjs +0 -31
- package/dist/lib/browser/chunk-QFRRLZVL.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -554
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/translations.mjs +0 -9
- package/dist/lib/browser/translations.mjs.map +0 -7
|
@@ -1,554 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
translationKey
|
|
3
|
-
} from "./chunk-QFRRLZVL.mjs";
|
|
4
|
-
|
|
5
|
-
// src/Thread/Thread.tsx
|
|
6
|
-
import React2, { forwardRef as forwardRef2, useCallback as useCallback2, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
7
|
-
import { Obj as Obj2 } from "@dxos/echo";
|
|
8
|
-
import { Icon, IconButton as IconButton2, ScrollArea, composable, composableProps, useThemeContext as useThemeContext2, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
9
|
-
import { Mosaic } from "@dxos/react-ui-mosaic";
|
|
10
|
-
import { createBasicExtensions as createBasicExtensions2, createThemeExtensions as createThemeExtensions2, listener as listener2 } from "@dxos/ui-editor";
|
|
11
|
-
import { hoverableControlItem as hoverableControlItem2, hoverableControls as hoverableControls2, hoverableFocusedWithinControls as hoverableFocusedWithinControls2, mx as mx3 } from "@dxos/ui-theme";
|
|
12
|
-
|
|
13
|
-
// src/command.ts
|
|
14
|
-
import { HighlightStyle, StreamLanguage, syntaxHighlighting } from "@codemirror/language";
|
|
15
|
-
import { EditorView } from "@codemirror/view";
|
|
16
|
-
import { tags } from "@dxos/ui-editor";
|
|
17
|
-
import { mx } from "@dxos/ui-theme";
|
|
18
|
-
var parser = StreamLanguage.define({
|
|
19
|
-
startState: () => ({
|
|
20
|
-
count: 0
|
|
21
|
-
}),
|
|
22
|
-
token: (stream, state) => {
|
|
23
|
-
state.count++;
|
|
24
|
-
if (stream.eatSpace()) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
if (state.count === 1 && stream.match(/^\/\w+/)) {
|
|
28
|
-
return "tagName";
|
|
29
|
-
}
|
|
30
|
-
if (stream.match(/^@\w+/)) {
|
|
31
|
-
return "labelName";
|
|
32
|
-
}
|
|
33
|
-
stream.next();
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
var styles = HighlightStyle.define([
|
|
38
|
-
{
|
|
39
|
-
tag: tags.tagName,
|
|
40
|
-
class: mx("dx-tag dx-tag--indigo")
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
tag: tags.labelName,
|
|
44
|
-
class: mx("dx-tag dx-tag--blue")
|
|
45
|
-
}
|
|
46
|
-
]);
|
|
47
|
-
var theme = EditorView.theme({
|
|
48
|
-
".dx-tag": {
|
|
49
|
-
verticalAlign: "bottom"
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
var command = [
|
|
53
|
-
parser,
|
|
54
|
-
syntaxHighlighting(styles),
|
|
55
|
-
theme
|
|
56
|
-
];
|
|
57
|
-
|
|
58
|
-
// src/context.ts
|
|
59
|
-
import { createContext } from "@radix-ui/react-context";
|
|
60
|
-
var [ThreadContextProvider, useThreadContext] = createContext("Thread");
|
|
61
|
-
|
|
62
|
-
// src/Message/Message.tsx
|
|
63
|
-
import { EditorView as EditorView2 } from "@codemirror/view";
|
|
64
|
-
import { formatDistanceToNow } from "date-fns/formatDistanceToNow";
|
|
65
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
66
|
-
import { Obj, Ref } from "@dxos/echo";
|
|
67
|
-
import { Avatar, IconButton, useOnTransition, useThemeContext, useTranslation } from "@dxos/react-ui";
|
|
68
|
-
import { useTextEditor } from "@dxos/react-ui-editor";
|
|
69
|
-
import { createBasicExtensions, createThemeExtensions, keymap, listener } from "@dxos/ui-editor";
|
|
70
|
-
import { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx as mx2 } from "@dxos/ui-theme";
|
|
71
|
-
import { hexToEmoji, hexToHue, isTruthy } from "@dxos/util";
|
|
72
|
-
var avatarSize = 7;
|
|
73
|
-
var buttonGroupClassNames = "flex flex-row items-center gap-0.5 pe-2";
|
|
74
|
-
var buttonClassNames = "p-1! transition-opacity";
|
|
75
|
-
var MessageRoot = /* @__PURE__ */ forwardRef(({ authorImgSrc, authorId, authorName, authorAvatarProps, continues = true, controls, children, classNames, ...rootProps }, forwardedRef) => {
|
|
76
|
-
return /* @__PURE__ */ React.createElement(Avatar.Root, null, /* @__PURE__ */ React.createElement("div", {
|
|
77
|
-
"data-testid": "thread.message",
|
|
78
|
-
...rootProps,
|
|
79
|
-
className: mx2("grid grid-cols-[var(--dx-rail-size)_1fr_min-content] w-full", classNames),
|
|
80
|
-
ref: forwardedRef
|
|
81
|
-
}, /* @__PURE__ */ React.createElement("div", {
|
|
82
|
-
className: "flex flex-col items-center gap-2 pt-1"
|
|
83
|
-
}, /* @__PURE__ */ React.createElement(Avatar.Content, {
|
|
84
|
-
size: avatarSize,
|
|
85
|
-
hue: authorAvatarProps?.hue || hexToHue(authorId ?? "0"),
|
|
86
|
-
fallback: authorAvatarProps?.emoji || hexToEmoji(authorId ?? "0"),
|
|
87
|
-
...authorImgSrc && {
|
|
88
|
-
imgSrc: authorImgSrc
|
|
89
|
-
}
|
|
90
|
-
}), continues && /* @__PURE__ */ React.createElement("div", {
|
|
91
|
-
className: "w-px grow bg-separator"
|
|
92
|
-
})), /* @__PURE__ */ React.createElement("div", {
|
|
93
|
-
className: "py-1 min-w-0"
|
|
94
|
-
}, children), controls && /* @__PURE__ */ React.createElement("div", {
|
|
95
|
-
className: "self-start"
|
|
96
|
-
}, controls)));
|
|
97
|
-
});
|
|
98
|
-
MessageRoot.displayName = "Message.Root";
|
|
99
|
-
var MessageHeading = ({ children, classNames, timestamp, authorName, ...props }) => {
|
|
100
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
101
|
-
...props,
|
|
102
|
-
className: mx2("flex gap-2 items-start", classNames)
|
|
103
|
-
}, /* @__PURE__ */ React.createElement("p", {
|
|
104
|
-
className: "grow"
|
|
105
|
-
}, /* @__PURE__ */ React.createElement(MessageAuthorName, {
|
|
106
|
-
authorName
|
|
107
|
-
}), timestamp && /* @__PURE__ */ React.createElement(MessageTime, {
|
|
108
|
-
timestamp
|
|
109
|
-
})), children);
|
|
110
|
-
};
|
|
111
|
-
MessageHeading.displayName = "Message.Heading";
|
|
112
|
-
var MessageAuthorName = ({ authorName }) => {
|
|
113
|
-
const { t } = useTranslation(translationKey);
|
|
114
|
-
return /* @__PURE__ */ React.createElement(Avatar.Label, {
|
|
115
|
-
classNames: "block truncate text-sm text-subdued"
|
|
116
|
-
}, authorName ?? t("anonymous.label"));
|
|
117
|
-
};
|
|
118
|
-
MessageAuthorName.displayName = "Message.AuthorName";
|
|
119
|
-
var MessageTime = ({ timestamp }) => {
|
|
120
|
-
const { dtLocale } = useTranslation(translationKey);
|
|
121
|
-
const dt = timestamp ? new Date(timestamp) : void 0;
|
|
122
|
-
return /* @__PURE__ */ React.createElement("time", {
|
|
123
|
-
className: "block text-subdued text-xs pb-0.5",
|
|
124
|
-
dateTime: dt?.toISOString()
|
|
125
|
-
}, dt ? formatDistanceToNow(dt, {
|
|
126
|
-
locale: dtLocale,
|
|
127
|
-
addSuffix: true
|
|
128
|
-
}) : "");
|
|
129
|
-
};
|
|
130
|
-
MessageTime.displayName = "Message.Time";
|
|
131
|
-
var MessageBody = ({ message, isAuthor, editing, onSave }) => {
|
|
132
|
-
const { components } = useThreadContext("Message.Body");
|
|
133
|
-
const textBlockIndex = message.blocks.findIndex((block) => block._tag === "text");
|
|
134
|
-
const textBlock = textBlockIndex !== -1 ? message.blocks[textBlockIndex] : void 0;
|
|
135
|
-
const proposalBlock = message.blocks.find((block) => block._tag === "proposal");
|
|
136
|
-
const references = message.blocks.filter((block) => block._tag === "reference").map((block) => block.reference);
|
|
137
|
-
const Object = components.Object;
|
|
138
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, textBlock && /* @__PURE__ */ React.createElement(TextBlock, {
|
|
139
|
-
block: textBlock,
|
|
140
|
-
isAuthor,
|
|
141
|
-
editing,
|
|
142
|
-
onSave
|
|
143
|
-
}), proposalBlock && /* @__PURE__ */ React.createElement("div", {
|
|
144
|
-
className: "me-4 italic"
|
|
145
|
-
}, proposalBlock.text), Object && Ref.Array.targets(references).map((reference, index) => /* @__PURE__ */ React.createElement(Object, {
|
|
146
|
-
key: index,
|
|
147
|
-
subject: reference
|
|
148
|
-
})));
|
|
149
|
-
};
|
|
150
|
-
MessageBody.displayName = "Message.Body";
|
|
151
|
-
var TextBlock = ({ block, isAuthor, editing, onSave }) => {
|
|
152
|
-
const { themeMode } = useThemeContext();
|
|
153
|
-
const inMemoryContentRef = useRef(block.text);
|
|
154
|
-
const handleDocumentChange = useCallback((next) => {
|
|
155
|
-
inMemoryContentRef.current = next;
|
|
156
|
-
}, []);
|
|
157
|
-
const saveDocumentChange = useCallback(() => {
|
|
158
|
-
onSave?.(inMemoryContentRef.current);
|
|
159
|
-
}, [
|
|
160
|
-
onSave
|
|
161
|
-
]);
|
|
162
|
-
useOnTransition(editing, true, false, saveDocumentChange);
|
|
163
|
-
const { parentRef, focusAttributes, view } = useTextEditor(() => ({
|
|
164
|
-
initialValue: block.text,
|
|
165
|
-
extensions: [
|
|
166
|
-
createBasicExtensions({
|
|
167
|
-
readOnly: !isAuthor || !editing
|
|
168
|
-
}),
|
|
169
|
-
createThemeExtensions({
|
|
170
|
-
themeMode
|
|
171
|
-
}),
|
|
172
|
-
command,
|
|
173
|
-
EditorView2.updateListener.of((update) => {
|
|
174
|
-
if (update.docChanged) {
|
|
175
|
-
handleDocumentChange(update.state.doc.toString());
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
]
|
|
179
|
-
}), [
|
|
180
|
-
block.text,
|
|
181
|
-
editing,
|
|
182
|
-
isAuthor,
|
|
183
|
-
themeMode,
|
|
184
|
-
handleDocumentChange
|
|
185
|
-
]);
|
|
186
|
-
useEffect(() => {
|
|
187
|
-
if (editing) {
|
|
188
|
-
view?.focus();
|
|
189
|
-
}
|
|
190
|
-
}, [
|
|
191
|
-
editing,
|
|
192
|
-
view
|
|
193
|
-
]);
|
|
194
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
195
|
-
ref: parentRef,
|
|
196
|
-
className: "me-4",
|
|
197
|
-
...focusAttributes
|
|
198
|
-
});
|
|
199
|
-
};
|
|
200
|
-
var keyBindings = ({ onSend, onClear }) => [
|
|
201
|
-
{
|
|
202
|
-
key: "Enter",
|
|
203
|
-
run: () => {
|
|
204
|
-
if (onSend) {
|
|
205
|
-
onSend();
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
key: "Meta+Backspace",
|
|
213
|
-
run: () => {
|
|
214
|
-
if (onClear) {
|
|
215
|
-
onClear();
|
|
216
|
-
return true;
|
|
217
|
-
}
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
];
|
|
222
|
-
var MessageTextbox = /* @__PURE__ */ forwardRef(({ id, authorId, authorName, authorImgSrc, authorAvatarProps, disabled, extensions, onSend, onClear, onEditorFocus, ...editorProps }, forwardedRef) => {
|
|
223
|
-
const { parentRef, focusAttributes, view } = useTextEditor(() => ({
|
|
224
|
-
id,
|
|
225
|
-
extensions: [
|
|
226
|
-
keymap.of(keyBindings({
|
|
227
|
-
onSend,
|
|
228
|
-
onClear
|
|
229
|
-
})),
|
|
230
|
-
listener({
|
|
231
|
-
onFocus: ({ focusing }) => {
|
|
232
|
-
if (focusing) {
|
|
233
|
-
onEditorFocus?.();
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}),
|
|
237
|
-
extensions
|
|
238
|
-
].filter(isTruthy),
|
|
239
|
-
...editorProps
|
|
240
|
-
}), [
|
|
241
|
-
id,
|
|
242
|
-
extensions
|
|
243
|
-
]);
|
|
244
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
245
|
-
focus: () => view?.focus()
|
|
246
|
-
}), [
|
|
247
|
-
view
|
|
248
|
-
]);
|
|
249
|
-
return /* @__PURE__ */ React.createElement(MessageRoot, {
|
|
250
|
-
id,
|
|
251
|
-
authorId,
|
|
252
|
-
authorName,
|
|
253
|
-
authorImgSrc,
|
|
254
|
-
authorAvatarProps,
|
|
255
|
-
continues: false
|
|
256
|
-
}, /* @__PURE__ */ React.createElement("div", {
|
|
257
|
-
ref: parentRef,
|
|
258
|
-
className: mx2("py-0.5 me-1 rounded-xs dx-focus-ring", disabled && "opacity-50"),
|
|
259
|
-
...focusAttributes
|
|
260
|
-
}));
|
|
261
|
-
});
|
|
262
|
-
MessageTextbox.displayName = "Message.Textbox";
|
|
263
|
-
var MessageTile = ({ message, classNames }) => {
|
|
264
|
-
const { t } = useTranslation(translationKey);
|
|
265
|
-
const { getMetadata, identityDid, editable, onMessageDelete, onAcceptProposal } = useThreadContext("Message.Tile");
|
|
266
|
-
const [editing, setEditing] = useState(false);
|
|
267
|
-
const metadata = getMetadata(message);
|
|
268
|
-
const isAuthor = !!identityDid && identityDid === metadata.authorId;
|
|
269
|
-
const hasProposal = message.blocks.some((block) => block._tag === "proposal");
|
|
270
|
-
const handleEdit = useCallback(() => setEditing((value) => !value), []);
|
|
271
|
-
const handleDelete = useCallback(() => onMessageDelete?.(message.id), [
|
|
272
|
-
onMessageDelete,
|
|
273
|
-
message.id
|
|
274
|
-
]);
|
|
275
|
-
const handleAcceptProposal = useCallback(() => onAcceptProposal?.(message.id), [
|
|
276
|
-
onAcceptProposal,
|
|
277
|
-
message.id
|
|
278
|
-
]);
|
|
279
|
-
const handleSave = useCallback((text) => {
|
|
280
|
-
Obj.update(message, (message2) => {
|
|
281
|
-
const block = message2.blocks.find((block2) => block2._tag === "text");
|
|
282
|
-
if (block && block._tag === "text") {
|
|
283
|
-
block.text = text;
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
}, [
|
|
287
|
-
message
|
|
288
|
-
]);
|
|
289
|
-
const showEdit = isAuthor && editable;
|
|
290
|
-
const showAccept = hasProposal && !!onAcceptProposal;
|
|
291
|
-
const showDelete = !!onMessageDelete;
|
|
292
|
-
const controls = showEdit || showAccept || showDelete ? /* @__PURE__ */ React.createElement("div", {
|
|
293
|
-
className: buttonGroupClassNames
|
|
294
|
-
}, showEdit && /* @__PURE__ */ React.createElement(IconButton, {
|
|
295
|
-
"data-testid": editing ? "thread.message.save" : "thread.message.edit",
|
|
296
|
-
variant: "ghost",
|
|
297
|
-
icon: editing ? "ph--check--regular" : "ph--pencil-simple--regular",
|
|
298
|
-
iconOnly: true,
|
|
299
|
-
label: t(editing ? "save-message.label" : "edit-message.label"),
|
|
300
|
-
classNames: [
|
|
301
|
-
buttonClassNames,
|
|
302
|
-
hoverableControlItem
|
|
303
|
-
],
|
|
304
|
-
onClick: handleEdit
|
|
305
|
-
}), showAccept && /* @__PURE__ */ React.createElement(IconButton, {
|
|
306
|
-
"data-testid": "thread.message.accept",
|
|
307
|
-
variant: "ghost",
|
|
308
|
-
icon: "ph--check--regular",
|
|
309
|
-
iconOnly: true,
|
|
310
|
-
label: t("accept-proposal.label"),
|
|
311
|
-
classNames: [
|
|
312
|
-
buttonClassNames,
|
|
313
|
-
hoverableControlItem
|
|
314
|
-
],
|
|
315
|
-
onClick: handleAcceptProposal
|
|
316
|
-
}), showDelete && /* @__PURE__ */ React.createElement(IconButton, {
|
|
317
|
-
"data-testid": "thread.message.delete",
|
|
318
|
-
variant: "ghost",
|
|
319
|
-
icon: "ph--x--regular",
|
|
320
|
-
iconOnly: true,
|
|
321
|
-
label: t("delete-message.label"),
|
|
322
|
-
classNames: [
|
|
323
|
-
buttonClassNames,
|
|
324
|
-
hoverableControlItem
|
|
325
|
-
],
|
|
326
|
-
onClick: handleDelete
|
|
327
|
-
})) : void 0;
|
|
328
|
-
return /* @__PURE__ */ React.createElement(MessageRoot, {
|
|
329
|
-
...metadata,
|
|
330
|
-
controls,
|
|
331
|
-
classNames: [
|
|
332
|
-
hoverableControls,
|
|
333
|
-
hoverableFocusedWithinControls,
|
|
334
|
-
classNames
|
|
335
|
-
]
|
|
336
|
-
}, /* @__PURE__ */ React.createElement(MessageHeading, {
|
|
337
|
-
authorName: metadata.authorName,
|
|
338
|
-
timestamp: metadata.timestamp
|
|
339
|
-
}), /* @__PURE__ */ React.createElement(MessageBody, {
|
|
340
|
-
message,
|
|
341
|
-
isAuthor,
|
|
342
|
-
editing,
|
|
343
|
-
onSave: handleSave
|
|
344
|
-
}));
|
|
345
|
-
};
|
|
346
|
-
MessageTile.displayName = "Message.Tile";
|
|
347
|
-
var Message = {
|
|
348
|
-
Root: MessageRoot,
|
|
349
|
-
Heading: MessageHeading,
|
|
350
|
-
AuthorName: MessageAuthorName,
|
|
351
|
-
Time: MessageTime,
|
|
352
|
-
Body: MessageBody,
|
|
353
|
-
Textbox: MessageTextbox,
|
|
354
|
-
Tile: MessageTile
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
// src/Thread/Thread.tsx
|
|
358
|
-
var getMessageId = (message) => Obj2.getURI(message);
|
|
359
|
-
var ThreadRoot = ({ children, getMetadata, components, identityDid, editable, onMessageDelete, onAcceptProposal }) => {
|
|
360
|
-
const composerFocus = useRef2(void 0);
|
|
361
|
-
const registerComposerFocus = useCallback2((focus) => {
|
|
362
|
-
composerFocus.current = focus;
|
|
363
|
-
}, []);
|
|
364
|
-
const focusComposer = useCallback2(() => composerFocus.current?.(), []);
|
|
365
|
-
return /* @__PURE__ */ React2.createElement(ThreadContextProvider, {
|
|
366
|
-
getMetadata,
|
|
367
|
-
components: components ?? {},
|
|
368
|
-
identityDid,
|
|
369
|
-
editable,
|
|
370
|
-
registerComposerFocus,
|
|
371
|
-
focusComposer,
|
|
372
|
-
onMessageDelete,
|
|
373
|
-
onAcceptProposal
|
|
374
|
-
}, /* @__PURE__ */ React2.createElement(Mosaic.Root, null, children));
|
|
375
|
-
};
|
|
376
|
-
ThreadRoot.displayName = "Thread.Root";
|
|
377
|
-
var ThreadContent = composable(({ children, current, id, ...props }, forwardedRef) => {
|
|
378
|
-
return /* @__PURE__ */ React2.createElement("div", {
|
|
379
|
-
...composableProps(props, {
|
|
380
|
-
role: "group",
|
|
381
|
-
classNames: [
|
|
382
|
-
"flex flex-col bg-[var(--surface-bg)] current-related dx-attention-surface [--controls-opacity:0]",
|
|
383
|
-
hoverableFocusedWithinControls2
|
|
384
|
-
]
|
|
385
|
-
}),
|
|
386
|
-
"data-testid": "thread",
|
|
387
|
-
id,
|
|
388
|
-
"aria-current": current ? "location" : void 0,
|
|
389
|
-
ref: forwardedRef
|
|
390
|
-
}, children);
|
|
391
|
-
});
|
|
392
|
-
ThreadContent.displayName = "Thread.Content";
|
|
393
|
-
var ThreadHeader = composable(({ title, detached, current, controls, onSelect, ...props }, forwardedRef) => {
|
|
394
|
-
const { t } = useTranslation2(translationKey);
|
|
395
|
-
const { focusComposer } = useThreadContext("Thread.Header");
|
|
396
|
-
const handleSelect = useCallback2(() => {
|
|
397
|
-
onSelect?.();
|
|
398
|
-
focusComposer();
|
|
399
|
-
}, [
|
|
400
|
-
onSelect,
|
|
401
|
-
focusComposer
|
|
402
|
-
]);
|
|
403
|
-
return /* @__PURE__ */ React2.createElement("div", {
|
|
404
|
-
...composableProps(props, {
|
|
405
|
-
classNames: [
|
|
406
|
-
"grid grid-cols-[var(--dx-rail-size)_1fr_min-content] items-center",
|
|
407
|
-
hoverableControls2,
|
|
408
|
-
hoverableFocusedWithinControls2
|
|
409
|
-
]
|
|
410
|
-
}),
|
|
411
|
-
ref: forwardedRef
|
|
412
|
-
}, /* @__PURE__ */ React2.createElement("div", {
|
|
413
|
-
className: "flex items-center justify-center"
|
|
414
|
-
}, /* @__PURE__ */ React2.createElement(IconButton2, {
|
|
415
|
-
iconOnly: true,
|
|
416
|
-
variant: "ghost",
|
|
417
|
-
density: "sm",
|
|
418
|
-
icon: "ph--caret-double-right--regular",
|
|
419
|
-
label: t("select-thread.label"),
|
|
420
|
-
classNames: "text-description",
|
|
421
|
-
onClick: handleSelect
|
|
422
|
-
})), /* @__PURE__ */ React2.createElement("div", {
|
|
423
|
-
className: "flex items-center overflow-hidden"
|
|
424
|
-
}, /* @__PURE__ */ React2.createElement("p", {
|
|
425
|
-
role: "heading",
|
|
426
|
-
"data-testid": "thread.heading",
|
|
427
|
-
className: mx3("me-2 font-medium truncate italic", current ? "text-accent-text" : "text-description", detached && "line-through decoration-1")
|
|
428
|
-
}, title)), controls);
|
|
429
|
-
});
|
|
430
|
-
ThreadHeader.displayName = "Thread.Header";
|
|
431
|
-
var MessageTileAdapter = ({ id, data, location, draggable, current, selected }) => /* @__PURE__ */ React2.createElement(Mosaic.Tile, {
|
|
432
|
-
id,
|
|
433
|
-
data,
|
|
434
|
-
location,
|
|
435
|
-
draggable,
|
|
436
|
-
current,
|
|
437
|
-
selected
|
|
438
|
-
}, /* @__PURE__ */ React2.createElement(Message.Tile, {
|
|
439
|
-
message: data
|
|
440
|
-
}));
|
|
441
|
-
var ThreadMessages = ({ messages, estimateSize = 80, currentId, classNames }) => {
|
|
442
|
-
const [viewport, setViewport] = useState2(null);
|
|
443
|
-
const items = useMemo(() => messages.filter(Boolean), [
|
|
444
|
-
messages
|
|
445
|
-
]);
|
|
446
|
-
return /* @__PURE__ */ React2.createElement(Mosaic.Container, {
|
|
447
|
-
asChild: true,
|
|
448
|
-
orientation: "vertical",
|
|
449
|
-
autoScroll: viewport,
|
|
450
|
-
currentId,
|
|
451
|
-
eventHandler: {
|
|
452
|
-
id: "thread",
|
|
453
|
-
canDrop: () => false
|
|
454
|
-
}
|
|
455
|
-
}, /* @__PURE__ */ React2.createElement(ScrollArea.Root, {
|
|
456
|
-
classNames: mx3("col-span-2", classNames),
|
|
457
|
-
orientation: "vertical"
|
|
458
|
-
}, /* @__PURE__ */ React2.createElement(ScrollArea.Viewport, {
|
|
459
|
-
ref: setViewport
|
|
460
|
-
}, /* @__PURE__ */ React2.createElement(Mosaic.VirtualStack, {
|
|
461
|
-
items,
|
|
462
|
-
getId: getMessageId,
|
|
463
|
-
Tile: MessageTileAdapter,
|
|
464
|
-
draggable: false,
|
|
465
|
-
getScrollElement: () => viewport,
|
|
466
|
-
estimateSize: () => estimateSize
|
|
467
|
-
}))));
|
|
468
|
-
};
|
|
469
|
-
ThreadMessages.displayName = "Thread.Messages";
|
|
470
|
-
var ThreadTextbox = ({ placeholder, autoFocus, disabled, extensions, onSend, ...metadata }) => {
|
|
471
|
-
const { t } = useTranslation2(translationKey);
|
|
472
|
-
const { themeMode } = useThemeContext2();
|
|
473
|
-
const { registerComposerFocus } = useThreadContext("Thread.Textbox");
|
|
474
|
-
const composerRef = useRef2(null);
|
|
475
|
-
const messageRef = useRef2("");
|
|
476
|
-
const [count, setCount] = useState2(0);
|
|
477
|
-
useEffect2(() => {
|
|
478
|
-
registerComposerFocus(() => composerRef.current?.focus());
|
|
479
|
-
return () => registerComposerFocus(void 0);
|
|
480
|
-
}, [
|
|
481
|
-
registerComposerFocus
|
|
482
|
-
]);
|
|
483
|
-
const editorExtensions = useMemo(() => [
|
|
484
|
-
createBasicExtensions2({
|
|
485
|
-
placeholder: placeholder ?? t("message.placeholder")
|
|
486
|
-
}),
|
|
487
|
-
createThemeExtensions2({
|
|
488
|
-
themeMode
|
|
489
|
-
}),
|
|
490
|
-
listener2({
|
|
491
|
-
onChange: ({ text }) => messageRef.current = text
|
|
492
|
-
}),
|
|
493
|
-
command,
|
|
494
|
-
extensions
|
|
495
|
-
].filter(Boolean), [
|
|
496
|
-
themeMode,
|
|
497
|
-
placeholder,
|
|
498
|
-
t,
|
|
499
|
-
extensions,
|
|
500
|
-
count
|
|
501
|
-
]);
|
|
502
|
-
const handleSend = useCallback2(() => {
|
|
503
|
-
const text = messageRef.current;
|
|
504
|
-
if (!text?.length || !onSend) {
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
if (onSend(text)) {
|
|
508
|
-
messageRef.current = "";
|
|
509
|
-
setCount((value) => value + 1);
|
|
510
|
-
}
|
|
511
|
-
}, []);
|
|
512
|
-
return /* @__PURE__ */ React2.createElement(Message.Textbox, {
|
|
513
|
-
ref: composerRef,
|
|
514
|
-
...metadata,
|
|
515
|
-
autoFocus,
|
|
516
|
-
disabled,
|
|
517
|
-
extensions: editorExtensions,
|
|
518
|
-
onSend: handleSend
|
|
519
|
-
});
|
|
520
|
-
};
|
|
521
|
-
ThreadTextbox.displayName = "Thread.Textbox";
|
|
522
|
-
var ThreadStatus = /* @__PURE__ */ forwardRef2(({ activity, classNames, children, ...props }, forwardedRef) => {
|
|
523
|
-
const { t } = useTranslation2(translationKey);
|
|
524
|
-
return /* @__PURE__ */ React2.createElement("div", {
|
|
525
|
-
...props,
|
|
526
|
-
className: mx3("col-start-2 grid grid-cols-[min-content_1fr_max-content] pb-2 pe-2 text-xs text-description", classNames),
|
|
527
|
-
ref: forwardedRef
|
|
528
|
-
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
529
|
-
icon: "ph--spinner--bold",
|
|
530
|
-
classNames: "w-6 h-4 invisible data-[visible=show]:visible animate-spin-slow",
|
|
531
|
-
"data-visible": activity ? "show" : "hide"
|
|
532
|
-
}), /* @__PURE__ */ React2.createElement("span", {
|
|
533
|
-
className: "truncate min-w-0",
|
|
534
|
-
"aria-live": "polite"
|
|
535
|
-
}, activity ? children : null), /* @__PURE__ */ React2.createElement("span", {
|
|
536
|
-
className: mx3("text-end", hoverableControlItem2)
|
|
537
|
-
}, t("enter-to-send.message")));
|
|
538
|
-
});
|
|
539
|
-
ThreadStatus.displayName = "Thread.Status";
|
|
540
|
-
var Thread = {
|
|
541
|
-
Root: ThreadRoot,
|
|
542
|
-
Content: ThreadContent,
|
|
543
|
-
Header: ThreadHeader,
|
|
544
|
-
Messages: ThreadMessages,
|
|
545
|
-
Textbox: ThreadTextbox,
|
|
546
|
-
Status: ThreadStatus
|
|
547
|
-
};
|
|
548
|
-
export {
|
|
549
|
-
Message,
|
|
550
|
-
Thread,
|
|
551
|
-
command,
|
|
552
|
-
useThreadContext
|
|
553
|
-
};
|
|
554
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/Thread/Thread.tsx", "../../../src/command.ts", "../../../src/context.ts", "../../../src/Message/Message.tsx"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport React, {\n type ComponentPropsWithRef,\n type PropsWithChildren,\n type ReactNode,\n forwardRef,\n useCallback,\n useEffect,\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 { 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) and the Mosaic root that `Thread.Messages`\n * renders its virtual stack within. Renders no DOM of its own — wrap the visible\n * thread chrome in `Thread.Content`.\n */\nconst ThreadRoot = ({\n children,\n getMetadata,\n components,\n identityDid,\n editable,\n onMessageDelete,\n onAcceptProposal,\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 >\n <Mosaic.Root>{children}</Mosaic.Root>\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\nconst MessageTileAdapter = ({\n id,\n data,\n location,\n draggable,\n current,\n selected,\n}: MosaicTileProps<MessageType.Message>) => (\n <Mosaic.Tile id={id} data={data} location={location} draggable={draggable} current={current} selected={selected}>\n <Message.Tile message={data} />\n </Mosaic.Tile>\n);\n\nexport type ThreadMessagesProps = ThemedClassName<{\n messages: readonly MessageType.Message[];\n /** Estimated tile height for the virtualizer. */\n estimateSize?: number;\n currentId?: string;\n}>;\n\n/** Virtualized stack of message tiles (via Mosaic), within an internal scroll area. */\nconst ThreadMessages = ({ messages, estimateSize = 80, currentId, classNames }: ThreadMessagesProps) => {\n const [viewport, setViewport] = useState<HTMLElement | null>(null);\n const items = useMemo(() => messages.filter(Boolean), [messages]);\n\n return (\n <Mosaic.Container\n asChild\n orientation='vertical'\n autoScroll={viewport}\n currentId={currentId}\n eventHandler={{ id: 'thread', canDrop: () => false }}\n >\n <ScrollArea.Root classNames={mx('col-span-2', classNames)} orientation='vertical'>\n <ScrollArea.Viewport ref={setViewport}>\n <Mosaic.VirtualStack\n items={items}\n getId={getMessageId}\n Tile={MessageTileAdapter}\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", "//\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 { formatDistanceToNow } from 'date-fns/formatDistanceToNow';\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'>\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 text-sm text-subdued'>{authorName ?? t('anonymous.label')}</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='block text-subdued text-xs pb-0.5' dateTime={dt?.toISOString()}>\n {dt ? formatDistanceToNow(dt, { locale: dtLocale, addSuffix: true }) : ''}\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 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 {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};\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 }: MessageTileProps) => {\n const { t } = useTranslation(translationKey);\n const { getMetadata, identityDid, editable, onMessageDelete, onAcceptProposal } = 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\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 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 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 controls={controls}\n classNames={[hoverableControls, hoverableFocusedWithinControls, classNames]}\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// 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};\n"],
|
|
5
|
-
"mappings": ";;;;;AAIA,OAAOA,UAILC,cAAAA,aACAC,eAAAA,cACAC,aAAAA,YACAC,SACAC,UAAAA,SACAC,YAAAA,iBACK;AAEP,SAASC,OAAAA,YAAW;AACpB,SAEEC,MACAC,cAAAA,aACAC,YAEAC,YACAC,iBACAC,mBAAAA,kBACAC,kBAAAA,uBACK;AACP,SAASC,cAAoC;AAE7C,SAAyBC,yBAAAA,wBAAuBC,yBAAAA,wBAAuBC,YAAAA,iBAAgB;AACvF,SAASC,wBAAAA,uBAAsBC,qBAAAA,oBAAmBC,kCAAAA,iCAAgCC,MAAAA,WAAU;;;AC3B5F,SAASC,gBAAgBC,gBAAgBC,0BAA0B;AAEnE,SAASC,kBAAkB;AAE3B,SAASC,YAAY;AACrB,SAASC,UAAU;AAOnB,IAAMC,SAASL,eAAeM,OAA0B;EACtDC,YAAY,OAAO;IAAEC,OAAO;EAAE;EAC9BC,OAAO,CAACC,QAAQC,UAAAA;AACdA,UAAMH;AACN,QAAIE,OAAOE,SAAQ,GAAI;AACrB,aAAO;IACT;AAEA,QAAID,MAAMH,UAAU,KAAKE,OAAOG,MAAM,QAAA,GAAW;AAC/C,aAAO;IACT;AAEA,QAAIH,OAAOG,MAAM,OAAA,GAAU;AACzB,aAAO;IACT;AACAH,WAAOI,KAAI;AACX,WAAO;EACT;AACF,CAAA;AAEA,IAAMC,SAAShB,eAAeO,OAAO;EACnC;IACEU,KAAKb,KAAKc;IACVC,OAAOd,GAAG,uBAAA;EACZ;EACA;IACEY,KAAKb,KAAKgB;IACVD,OAAOd,GAAG,qBAAA;EACZ;CACD;AAMD,IAAMgB,QAAQlB,WAAWkB,MAAM;EAC7B,WAAW;IACTC,eAAe;EACjB;AACF,CAAA;AAEO,IAAMC,UAAqB;EAACjB;EAAQJ,mBAAmBc,MAAAA;EAASK;;;;ACrDvE,SAASG,qBAAqB;AAqBvB,IAAM,CAACC,uBAAuBC,gBAAAA,IAGjCF,cAA6B,QAAA;;;ACxBjC,SAASG,cAAAA,mBAAkB;AAC3B,SAASC,2BAA2B;AACpC,OAAOC,SAILC,YACAC,aACAC,WACAC,qBACAC,QACAC,gBACK;AAEP,SAASC,KAAKC,WAAW;AACzB,SACEC,QACAC,YAEAC,iBACAC,iBACAC,sBACK;AACP,SAAkCC,qBAAqB;AAEvD,SAASC,uBAAuBC,uBAAuBC,QAAQC,gBAAgB;AAC/E,SAASC,sBAAsBC,mBAAmBC,gCAAgCC,MAAAA,WAAU;AAC5F,SAASC,YAAYC,UAAUC,gBAAgB;AAO/C,IAAMC,aAAa;AAEnB,IAAMC,wBAAwB;AAC9B,IAAMC,mBAAmB;AAWzB,IAAMC,cAAcC,2BAClB,CACE,EACEC,cACAC,UACAC,YACAC,mBACAC,YAAY,MACZC,UACAC,UACAC,YACA,GAAGC,UAAAA,GAELC,iBAAAA;AAKA,SACE,sBAAA,cAACC,OAAOC,MAAI,MACV,sBAAA,cAACC,OAAAA;IACCC,eAAY;IACX,GAAGL;IACJM,WAAWC,IAAG,+DAA+DR,UAAAA;IAC7ES,KAAKP;KAEL,sBAAA,cAACG,OAAAA;IAAIE,WAAU;KACb,sBAAA,cAACJ,OAAOO,SAAO;IACbC,MAAMvB;IACNwB,KAAKhB,mBAAmBgB,OAAOC,SAASnB,YAAY,GAAA;IACpDoB,UAAUlB,mBAAmBmB,SAASC,WAAWtB,YAAY,GAAA;IAC5D,GAAID,gBAAgB;MAAEwB,QAAQxB;IAAa;MAE7CI,aAAa,sBAAA,cAACQ,OAAAA;IAAIE,WAAU;OAE/B,sBAAA,cAACF,OAAAA;IAAIE,WAAU;KAAgBR,QAAAA,GAC9BD,YAAY,sBAAA,cAACO,OAAAA;IAAIE,WAAU;KAAcT,QAAAA,CAAAA,CAAAA;AAIlD,CAAA;AAGFP,YAAY2B,cAAc;AAS1B,IAAMC,iBAAiB,CAAC,EAAEpB,UAAUC,YAAYoB,WAAWzB,YAAY,GAAG0B,MAAAA,MAA4B;AACpG,SACE,sBAAA,cAAChB,OAAAA;IAAK,GAAGgB;IAAOd,WAAWC,IAAG,0BAA0BR,UAAAA;KACtD,sBAAA,cAACsB,KAAAA;IAAEf,WAAU;KACX,sBAAA,cAACgB,mBAAAA;IAAkB5B;MAClByB,aAAa,sBAAA,cAACI,aAAAA;IAAYJ;OAE5BrB,QAAAA;AAGP;AAEAoB,eAAeD,cAAc;AAI7B,IAAMK,oBAAoB,CAAC,EAAE5B,WAAU,MAA0B;AAC/D,QAAM,EAAE8B,EAAC,IAAKC,eAAeC,cAAAA;AAC7B,SACE,sBAAA,cAACxB,OAAOyB,OAAK;IAAC5B,YAAW;KAAuCL,cAAc8B,EAAE,iBAAA,CAAA;AAEpF;AAEAF,kBAAkBL,cAAc;AAIhC,IAAMM,cAAc,CAAC,EAAEJ,UAAS,MAAoB;AAClD,QAAM,EAAES,SAAQ,IAAKH,eAAeC,cAAAA;AACpC,QAAMG,KAAKV,YAAY,IAAIW,KAAKX,SAAAA,IAAaY;AAC7C,SACE,sBAAA,cAACC,QAAAA;IAAK1B,WAAU;IAAoC2B,UAAUJ,IAAIK,YAAAA;KAC/DL,KAAKM,oBAAoBN,IAAI;IAAEO,QAAQR;IAAUS,WAAW;EAAK,CAAA,IAAK,EAAA;AAG7E;AAEAd,YAAYN,cAAc;AAqB1B,IAAMqB,cAAc,CAAC,EAAEC,SAASC,UAAUC,SAASC,OAAM,MAAoB;AAC3E,QAAM,EAAEC,WAAU,IAAKC,iBAAiB,cAAA;AACxC,QAAMC,iBAAiBN,QAAQO,OAAOC,UAAU,CAACC,UAAUA,MAAMC,SAAS,MAAA;AAC1E,QAAMC,YAAYL,mBAAmB,KAAMN,QAAQO,OAAOD,cAAAA,IAAwCd;AAClG,QAAMoB,gBAAgBZ,QAAQO,OAAOM,KAAK,CAACJ,UAAUA,MAAMC,SAAS,UAAA;AACpE,QAAMI,aAAad,QAAQO,OACxBQ,OAAO,CAACN,UAAUA,MAAMC,SAAS,WAAA,EACjCM,IAAI,CAACP,UAAWA,MAAiCQ,SAAS;AAC7D,QAAMC,SAASd,WAAWc;AAE1B,SACE,sBAAA,cAAA,MAAA,UAAA,MACGP,aAAa,sBAAA,cAACQ,WAAAA;IAAUV,OAAOE;IAAWV;IAAoBC;IAAkBC;MAChFS,iBAAiB,sBAAA,cAAC/C,OAAAA;IAAIE,WAAU;KAAe6C,cAAcQ,IAAI,GACjEF,UACCG,IAAIC,MAAMC,QAAQT,UAAAA,EAAYE,IAAI,CAACC,WAAWO,UAC5C,sBAAA,cAACN,QAAAA;IAAOO,KAAKD;IAAOE,SAAST;;AAIvC;AAEAlB,YAAYrB,cAAc;AAE1B,IAAMyC,YAAY,CAAC,EACjBV,OACAR,UACAC,SACAC,OAAM,MAMP;AACC,QAAM,EAAEwB,UAAS,IAAKC,gBAAAA;AACtB,QAAMC,qBAAqBC,OAAOrB,MAAMW,IAAI;AAE5C,QAAMW,uBAAuBC,YAAY,CAACC,SAAAA;AACxCJ,uBAAmBK,UAAUD;EAC/B,GAAG,CAAA,CAAE;AAEL,QAAME,qBAAqBH,YAAY,MAAA;AACrC7B,aAAS0B,mBAAmBK,OAAO;EACrC,GAAG;IAAC/B;GAAO;AAEXiC,kBAAgBlC,SAAS,MAAM,OAAOiC,kBAAAA;AAEtC,QAAM,EAAEE,WAAWC,iBAAiBC,KAAI,IAAKC,cAC3C,OAAO;IACLC,cAAchC,MAAMW;IACpBsB,YAAY;MACVC,sBAAsB;QAAEC,UAAU,CAAC3C,YAAY,CAACC;MAAQ,CAAA;MACxD2C,sBAAsB;QAAElB;MAAU,CAAA;MAClCmB;MACAC,YAAWC,eAAeC,GAAG,CAACC,WAAAA;AAC5B,YAAIA,OAAOC,YAAY;AACrBpB,+BAAqBmB,OAAOE,MAAMC,IAAIC,SAAQ,CAAA;QAChD;MACF,CAAA;;EAEJ,IACA;IAAC7C,MAAMW;IAAMlB;IAASD;IAAU0B;IAAWI;GAAqB;AAGlEwB,YAAU,MAAA;AACR,QAAIrD,SAAS;AACXqC,YAAMiB,MAAAA;IACR;EACF,GAAG;IAACtD;IAASqC;GAAK;AAElB,SAAO,sBAAA,cAAC1E,OAAAA;IAAII,KAAKoE;IAAWtE,WAAU;IAAQ,GAAGuE;;AACnD;AAcA,IAAMmB,cAAc,CAAC,EAAEC,QAAQC,QAAO,MAAwD;EAC5F;IACElC,KAAK;IACLmC,KAAK,MAAA;AACH,UAAIF,QAAQ;AACVA,eAAAA;AACA,eAAO;MACT;AACA,aAAO;IACT;EACF;EACA;IACEjC,KAAK;IACLmC,KAAK,MAAA;AACH,UAAID,SAAS;AACXA,gBAAAA;AACA,eAAO;MACT;AACA,aAAO;IACT;EACF;;AAKF,IAAME,iBAAiB7G,2BACrB,CACE,EACE8G,IACA5G,UACAC,YACAF,cACAG,mBACA2G,UACArB,YACAgB,QACAC,SACAK,eACA,GAAGC,YAAAA,GAELvG,iBAAAA;AAEA,QAAM,EAAE2E,WAAWC,iBAAiBC,KAAI,IAAKC,cAC3C,OAAO;IACLsB;IACApB,YAAY;MACVwB,OAAOjB,GAAGQ,YAAY;QAAEC;QAAQC;MAAQ,CAAA,CAAA;MACxCQ,SAAS;QACPC,SAAS,CAAC,EAAEC,SAAQ,MAAE;AACpB,cAAIA,UAAU;AACZL,4BAAAA;UACF;QACF;MACF,CAAA;MACAtB;MACA3B,OAAOuD,QAAAA;IACT,GAAGL;EACL,IACA;IAACH;IAAIpB;GAAW;AAGlB6B,sBAAoB7G,cAAc,OAAO;IAAE8F,OAAO,MAAMjB,MAAMiB,MAAAA;EAAQ,IAAI;IAACjB;GAAK;AAEhF,SACE,sBAAA,cAACxF,aAAAA;IAAkB+G;IAAI5G;IAAUC;IAAYF;IAAcG;IAAqBC,WAAW;KACzF,sBAAA,cAACQ,OAAAA;IACCI,KAAKoE;IACLtE,WAAWC,IAAG,wCAAwC+F,YAAY,YAAA;IACjE,GAAGzB;;AAIZ,CAAA;AAGFuB,eAAenF,cAAc;AAgB7B,IAAM8F,cAAc,CAAC,EAAExE,SAASxC,WAAU,MAAoB;AAC5D,QAAM,EAAEyB,EAAC,IAAKC,eAAeC,cAAAA;AAC7B,QAAM,EAAEsF,aAAaC,aAAaC,UAAUC,iBAAiBC,iBAAgB,IAAKxE,iBAAiB,cAAA;AACnG,QAAM,CAACH,SAAS4E,UAAAA,IAAcC,SAAS,KAAA;AAEvC,QAAMC,WAAWP,YAAYzE,OAAAA;AAC7B,QAAMC,WAAW,CAAC,CAACyE,eAAeA,gBAAgBM,SAAS9H;AAC3D,QAAM+H,cAAcjF,QAAQO,OAAO2E,KAAK,CAACzE,UAAUA,MAAMC,SAAS,UAAA;AAElE,QAAMyE,aAAanD,YAAY,MAAM8C,WAAW,CAACM,UAAU,CAACA,KAAAA,GAAQ,CAAA,CAAE;AACtE,QAAMC,eAAerD,YAAY,MAAM4C,kBAAkB5E,QAAQ8D,EAAE,GAAG;IAACc;IAAiB5E,QAAQ8D;GAAG;AACnG,QAAMwB,uBAAuBtD,YAAY,MAAM6C,mBAAmB7E,QAAQ8D,EAAE,GAAG;IAACe;IAAkB7E,QAAQ8D;GAAG;AAC7G,QAAMyB,aAAavD,YACjB,CAACZ,SAAAA;AACCoE,QAAItC,OAAOlD,SAAS,CAACA,aAAAA;AACnB,YAAMS,QAAQT,SAAQO,OAAOM,KAAK,CAACJ,WAAUA,OAAMC,SAAS,MAAA;AAC5D,UAAID,SAASA,MAAMC,SAAS,QAAQ;AAClCD,cAAMW,OAAOA;MACf;IACF,CAAA;EACF,GACA;IAACpB;GAAQ;AAGX,QAAMyF,WAAWxF,YAAY0E;AAC7B,QAAMe,aAAaT,eAAe,CAAC,CAACJ;AACpC,QAAMc,aAAa,CAAC,CAACf;AACrB,QAAMtH,WACJmI,YAAYC,cAAcC,aACxB,sBAAA,cAAC9H,OAAAA;IAAIE,WAAWlB;KACb4I,YACC,sBAAA,cAACG,YAAAA;IACC9H,eAAaoC,UAAU,wBAAwB;IAC/C2F,SAAQ;IACRC,MAAM5F,UAAU,uBAAuB;IACvC6F,UAAAA;IACAC,OAAO/G,EAAEiB,UAAU,uBAAuB,oBAAA;IAC1C1C,YAAY;MAACV;MAAkBmJ;;IAC/BC,SAASf;MAGZO,cACC,sBAAA,cAACE,YAAAA;IACC9H,eAAY;IACZ+H,SAAQ;IACRC,MAAK;IACLC,UAAAA;IACAC,OAAO/G,EAAE,uBAAA;IACTzB,YAAY;MAACV;MAAkBmJ;;IAC/BC,SAASZ;MAGZK,cACC,sBAAA,cAACC,YAAAA;IACC9H,eAAY;IACZ+H,SAAQ;IACRC,MAAK;IACLC,UAAAA;IACAC,OAAO/G,EAAE,sBAAA;IACTzB,YAAY;MAACV;MAAkBmJ;;IAC/BC,SAASb;QAIb7F;AAEN,SACE,sBAAA,cAACzC,aAAAA;IACE,GAAGiI;IACJ1H;IACAE,YAAY;MAAC2I;MAAmBC;MAAgC5I;;KAEhE,sBAAA,cAACmB,gBAAAA;IAAexB,YAAY6H,SAAS7H;IAAYyB,WAAWoG,SAASpG;MACrE,sBAAA,cAACmB,aAAAA;IAAYC;IAAkBC;IAAoBC;IAAkBC,QAAQoF;;AAGnF;AAEAf,YAAY9F,cAAc;AAMnB,IAAM2H,UAAU;EACrBzI,MAAMb;EACNuJ,SAAS3H;EACT4H,YAAYxH;EACZyH,MAAMxH;EACNyH,MAAM1G;EACN2G,SAAS7C;EACT8C,MAAMnC;AACR;;;AHxYA,IAAMoC,eAAe,CAACC,YAAiCC,KAAIC,OAAOF,OAAAA;AAgBlE,IAAMG,aAAa,CAAC,EAClBC,UACAC,aACAC,YACAC,aACAC,UACAC,iBACAC,iBAAgB,MACA;AAEhB,QAAMC,gBAAgBC,QAAiCC,MAAAA;AAEvD,QAAMC,wBAAwBC,aAAY,CAACC,UAAAA;AACzCL,kBAAcM,UAAUD;EAC1B,GAAG,CAAA,CAAE;AAEL,QAAME,gBAAgBH,aAAY,MAAMJ,cAAcM,UAAO,GAAM,CAAA,CAAE;AAErE,SACE,gBAAAE,OAAA,cAACC,uBAAAA;IACCf;IACAC,YAAYA,cAAc,CAAC;IAC3BC;IACAC;IACAM;IACAI;IACAT;IACAC;KAEA,gBAAAS,OAAA,cAACE,OAAOC,MAAI,MAAElB,QAAAA,CAAAA;AAGpB;AAEAD,WAAWoB,cAAc;AAczB,IAAMC,gBAAgBC,WACpB,CAAC,EAAErB,UAAUa,SAASS,IAAI,GAAGC,MAAAA,GAASC,iBAAAA;AACpC,SACE,gBAAAT,OAAA,cAACU,OAAAA;IACE,GAAGC,gBAAgBH,OAAO;MACzBI,MAAM;MACNC,YAAY;QACV;QACAC;;IAEJ,CAAA;IACAC,eAAY;IACZR;IACAS,gBAAclB,UAAU,aAAaJ;IACrCuB,KAAKR;KAEJxB,QAAAA;AAGP,CAAA;AAGFoB,cAAcD,cAAc;AA0B5B,IAAMc,eAAeZ,WACnB,CAAC,EAAEa,OAAOC,UAAUtB,SAASuB,UAAUC,UAAU,GAAGd,MAAAA,GAASC,iBAAAA;AAC3D,QAAM,EAAEc,EAAC,IAAKC,gBAAeC,cAAAA;AAC7B,QAAM,EAAE1B,cAAa,IAAK2B,iBAAiB,eAAA;AAC3C,QAAMC,eAAe/B,aAAY,MAAA;AAC/B0B,eAAAA;AACAvB,kBAAAA;EACF,GAAG;IAACuB;IAAUvB;GAAc;AAE5B,SACE,gBAAAC,OAAA,cAACU,OAAAA;IACE,GAAGC,gBAAgBH,OAAO;MACzBK,YAAY;QACV;QACAe;QACAd;;IAEJ,CAAA;IACAG,KAAKR;KAEL,gBAAAT,OAAA,cAACU,OAAAA;IAAImB,WAAU;KACb,gBAAA7B,OAAA,cAAC8B,aAAAA;IACCC,UAAAA;IACAC,SAAQ;IACRC,SAAQ;IACRC,MAAK;IACLC,OAAOZ,EAAE,qBAAA;IACTV,YAAW;IACXuB,SAAST;OAGb,gBAAA3B,OAAA,cAACU,OAAAA;IAAImB,WAAU;KACb,gBAAA7B,OAAA,cAACqC,KAAAA;IACCzB,MAAK;IACLG,eAAY;IACZc,WAAWS,IACT,oCACAxC,UAAU,qBAAqB,oBAC/BsB,YAAY,2BAAA;KAGbD,KAAAA,CAAAA,GAGJE,QAAAA;AAGP,CAAA;AAGFH,aAAad,cAAc;AAM3B,IAAMmC,qBAAqB,CAAC,EAC1BhC,IACAiC,MACAC,UACAC,WACA5C,SACA6C,SAAQ,MAER,gBAAA3C,OAAA,cAACE,OAAO0C,MAAI;EAACrC;EAAQiC;EAAYC;EAAoBC;EAAsB5C;EAAkB6C;GAC3F,gBAAA3C,OAAA,cAAC6C,QAAQD,MAAI;EAAC/D,SAAS2D;;AAY3B,IAAMM,iBAAiB,CAAC,EAAEC,UAAUC,eAAe,IAAIC,WAAWpC,WAAU,MAAuB;AACjG,QAAM,CAACqC,UAAUC,WAAAA,IAAeC,UAA6B,IAAA;AAC7D,QAAMC,QAAQC,QAAQ,MAAMP,SAASQ,OAAOC,OAAAA,GAAU;IAACT;GAAS;AAEhE,SACE,gBAAA/C,OAAA,cAACE,OAAOuD,WAAS;IACfC,SAAAA;IACAC,aAAY;IACZC,YAAYV;IACZD;IACAY,cAAc;MAAEtD,IAAI;MAAUuD,SAAS,MAAM;IAAM;KAEnD,gBAAA9D,OAAA,cAAC+D,WAAW5D,MAAI;IAACU,YAAYyB,IAAG,cAAczB,UAAAA;IAAa8C,aAAY;KACrE,gBAAA3D,OAAA,cAAC+D,WAAWC,UAAQ;IAAC/C,KAAKkC;KACxB,gBAAAnD,OAAA,cAACE,OAAO+D,cAAY;IAClBZ;IACAa,OAAOtF;IACPgE,MAAML;IACNG,WAAW;IACXyB,kBAAkB,MAAMjB;IACxBF,cAAc,MAAMA;;AAMhC;AAEAF,eAAe1C,cAAc;AAmB7B,IAAMgE,gBAAgB,CAAC,EAAEC,aAAaC,WAAWC,UAAUC,YAAYC,QAAQ,GAAGC,SAAAA,MAA8B;AAC9G,QAAM,EAAEnD,EAAC,IAAKC,gBAAeC,cAAAA;AAC7B,QAAM,EAAEkD,UAAS,IAAKC,iBAAAA;AACtB,QAAM,EAAEjF,sBAAqB,IAAK+B,iBAAiB,gBAAA;AACnD,QAAMmD,cAAcpF,QAAqC,IAAA;AACzD,QAAMqF,aAAarF,QAAO,EAAA;AAC1B,QAAM,CAACsF,OAAOC,QAAAA,IAAY5B,UAAS,CAAA;AAGnC6B,EAAAA,WAAU,MAAA;AACRtF,0BAAsB,MAAMkF,YAAY/E,SAASD,MAAAA,CAAAA;AACjD,WAAO,MAAMF,sBAAsBD,MAAAA;EACrC,GAAG;IAACC;GAAsB;AAE1B,QAAMuF,mBAAmB5B,QACvB,MACE;IACE6B,uBAAsB;MAAEd,aAAaA,eAAe9C,EAAE,qBAAA;IAAuB,CAAA;IAC7E6D,uBAAsB;MAAET;IAAU,CAAA;IAClCU,UAAS;MAAEC,UAAU,CAAC,EAAEC,KAAI,MAAQT,WAAWhF,UAAUyF;IAAM,CAAA;IAC/DC;IACAhB;IACAjB,OAAOC,OAAAA,GACX;IAACmB;IAAWN;IAAa9C;IAAGiD;IAAYO;GAAM;AAGhD,QAAMU,aAAa7F,aAAY,MAAA;AAC7B,UAAM2F,OAAOT,WAAWhF;AACxB,QAAI,CAACyF,MAAMG,UAAU,CAACjB,QAAQ;AAC5B;IACF;AACA,QAAIA,OAAOc,IAAAA,GAAO;AAChBT,iBAAWhF,UAAU;AACrBkF,eAAS,CAACW,UAAUA,QAAQ,CAAA;IAC9B;EACF,GAAG,CAAA,CAAE;AAEL,SACE,gBAAA3F,OAAA,cAAC6C,QAAQ+C,SAAO;IACd3E,KAAK4D;IACJ,GAAGH;IACJJ;IACAC;IACAC,YAAYU;IACZT,QAAQgB;;AAGd;AAEArB,cAAchE,cAAc;AAU5B,IAAMyF,eAAeC,gBAAAA,YACnB,CAAC,EAAEC,UAAUlF,YAAY5B,UAAU,GAAGuB,MAAAA,GAASC,iBAAAA;AAC7C,QAAM,EAAEc,EAAC,IAAKC,gBAAeC,cAAAA;AAC7B,SACE,gBAAAzB,OAAA,cAACU,OAAAA;IACE,GAAGF;IACJqB,WAAWS,IACT,+FACAzB,UAAAA;IAEFI,KAAKR;KAEL,gBAAAT,OAAA,cAACgG,MAAAA;IACC9D,MAAK;IACLrB,YAAW;IACXoF,gBAAcF,WAAW,SAAS;MAEpC,gBAAA/F,OAAA,cAACkG,QAAAA;IAAKrE,WAAU;IAAmBsE,aAAU;KAC1CJ,WAAW9G,WAAW,IAAA,GAEzB,gBAAAe,OAAA,cAACkG,QAAAA;IAAKrE,WAAWS,IAAG,YAAY8D,qBAAAA;KAAwB7E,EAAE,uBAAA,CAAA,CAAA;AAGhE,CAAA;AAGFsE,aAAazF,cAAc;AAMpB,IAAMiG,SAAS;EACpBlG,MAAMnB;EACNsH,SAASjG;EACTkG,QAAQrF;EACRsF,UAAU1D;EACV8C,SAASxB;EACTqC,QAAQZ;AACV;",
|
|
6
|
-
"names": ["React", "forwardRef", "useCallback", "useEffect", "useMemo", "useRef", "useState", "Obj", "Icon", "IconButton", "ScrollArea", "composable", "composableProps", "useThemeContext", "useTranslation", "Mosaic", "createBasicExtensions", "createThemeExtensions", "listener", "hoverableControlItem", "hoverableControls", "hoverableFocusedWithinControls", "mx", "HighlightStyle", "StreamLanguage", "syntaxHighlighting", "EditorView", "tags", "mx", "parser", "define", "startState", "count", "token", "stream", "state", "eatSpace", "match", "next", "styles", "tag", "tagName", "class", "labelName", "theme", "verticalAlign", "command", "createContext", "ThreadContextProvider", "useThreadContext", "EditorView", "formatDistanceToNow", "React", "forwardRef", "useCallback", "useEffect", "useImperativeHandle", "useRef", "useState", "Obj", "Ref", "Avatar", "IconButton", "useOnTransition", "useThemeContext", "useTranslation", "useTextEditor", "createBasicExtensions", "createThemeExtensions", "keymap", "listener", "hoverableControlItem", "hoverableControls", "hoverableFocusedWithinControls", "mx", "hexToEmoji", "hexToHue", "isTruthy", "avatarSize", "buttonGroupClassNames", "buttonClassNames", "MessageRoot", "forwardRef", "authorImgSrc", "authorId", "authorName", "authorAvatarProps", "continues", "controls", "children", "classNames", "rootProps", "forwardedRef", "Avatar", "Root", "div", "data-testid", "className", "mx", "ref", "Content", "size", "hue", "hexToHue", "fallback", "emoji", "hexToEmoji", "imgSrc", "displayName", "MessageHeading", "timestamp", "props", "p", "MessageAuthorName", "MessageTime", "t", "useTranslation", "translationKey", "Label", "dtLocale", "dt", "Date", "undefined", "time", "dateTime", "toISOString", "formatDistanceToNow", "locale", "addSuffix", "MessageBody", "message", "isAuthor", "editing", "onSave", "components", "useThreadContext", "textBlockIndex", "blocks", "findIndex", "block", "_tag", "textBlock", "proposalBlock", "find", "references", "filter", "map", "reference", "Object", "TextBlock", "text", "Ref", "Array", "targets", "index", "key", "subject", "themeMode", "useThemeContext", "inMemoryContentRef", "useRef", "handleDocumentChange", "useCallback", "next", "current", "saveDocumentChange", "useOnTransition", "parentRef", "focusAttributes", "view", "useTextEditor", "initialValue", "extensions", "createBasicExtensions", "readOnly", "createThemeExtensions", "command", "EditorView", "updateListener", "of", "update", "docChanged", "state", "doc", "toString", "useEffect", "focus", "keyBindings", "onSend", "onClear", "run", "MessageTextbox", "id", "disabled", "onEditorFocus", "editorProps", "keymap", "listener", "onFocus", "focusing", "isTruthy", "useImperativeHandle", "MessageTile", "getMetadata", "identityDid", "editable", "onMessageDelete", "onAcceptProposal", "setEditing", "useState", "metadata", "hasProposal", "some", "handleEdit", "value", "handleDelete", "handleAcceptProposal", "handleSave", "Obj", "showEdit", "showAccept", "showDelete", "IconButton", "variant", "icon", "iconOnly", "label", "hoverableControlItem", "onClick", "hoverableControls", "hoverableFocusedWithinControls", "Message", "Heading", "AuthorName", "Time", "Body", "Textbox", "Tile", "getMessageId", "message", "Obj", "getURI", "ThreadRoot", "children", "getMetadata", "components", "identityDid", "editable", "onMessageDelete", "onAcceptProposal", "composerFocus", "useRef", "undefined", "registerComposerFocus", "useCallback", "focus", "current", "focusComposer", "React", "ThreadContextProvider", "Mosaic", "Root", "displayName", "ThreadContent", "composable", "id", "props", "forwardedRef", "div", "composableProps", "role", "classNames", "hoverableFocusedWithinControls", "data-testid", "aria-current", "ref", "ThreadHeader", "title", "detached", "controls", "onSelect", "t", "useTranslation", "translationKey", "useThreadContext", "handleSelect", "hoverableControls", "className", "IconButton", "iconOnly", "variant", "density", "icon", "label", "onClick", "p", "mx", "MessageTileAdapter", "data", "location", "draggable", "selected", "Tile", "Message", "ThreadMessages", "messages", "estimateSize", "currentId", "viewport", "setViewport", "useState", "items", "useMemo", "filter", "Boolean", "Container", "asChild", "orientation", "autoScroll", "eventHandler", "canDrop", "ScrollArea", "Viewport", "VirtualStack", "getId", "getScrollElement", "ThreadTextbox", "placeholder", "autoFocus", "disabled", "extensions", "onSend", "metadata", "themeMode", "useThemeContext", "composerRef", "messageRef", "count", "setCount", "useEffect", "editorExtensions", "createBasicExtensions", "createThemeExtensions", "listener", "onChange", "text", "command", "handleSend", "length", "value", "Textbox", "ThreadStatus", "forwardRef", "activity", "Icon", "data-visible", "span", "aria-live", "hoverableControlItem", "Thread", "Content", "Header", "Messages", "Status"]
|
|
7
|
-
}
|