@dxos/react-ui-thread 0.14.0 → 0.16.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-thread",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "A set of components to use with threads, including comments and messages.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -41,15 +41,16 @@
|
|
|
41
41
|
"@codemirror/state": "^6.7.6",
|
|
42
42
|
"@codemirror/view": "^6.43.13",
|
|
43
43
|
"date-fns": "^3.6.0",
|
|
44
|
-
"@dxos/echo": "0.
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/react-
|
|
47
|
-
"@dxos/react-ui-
|
|
48
|
-
"@dxos/react-ui-
|
|
49
|
-
"@dxos/types": "0.
|
|
50
|
-
"@dxos/ui-
|
|
51
|
-
"@dxos/ui-
|
|
52
|
-
"@dxos/
|
|
44
|
+
"@dxos/echo-react": "0.16.0",
|
|
45
|
+
"@dxos/echo": "0.16.0",
|
|
46
|
+
"@dxos/react-hooks": "0.16.0",
|
|
47
|
+
"@dxos/react-ui-dnd": "0.16.0",
|
|
48
|
+
"@dxos/react-ui-editor": "0.16.0",
|
|
49
|
+
"@dxos/types": "0.16.0",
|
|
50
|
+
"@dxos/react-ui-mosaic": "0.16.0",
|
|
51
|
+
"@dxos/ui-editor": "0.16.0",
|
|
52
|
+
"@dxos/ui-types": "0.16.0",
|
|
53
|
+
"@dxos/util": "0.16.0"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
56
|
"@storybook/react-vite": "^10.6.0",
|
|
@@ -57,17 +58,17 @@
|
|
|
57
58
|
"@types/react-dom": "~19.2.3",
|
|
58
59
|
"react": "~19.2.7",
|
|
59
60
|
"react-dom": "~19.2.7",
|
|
60
|
-
"vite": "^8.
|
|
61
|
-
"@dxos/random": "0.
|
|
62
|
-
"@dxos/react-ui": "0.
|
|
63
|
-
"@dxos/schema": "0.
|
|
64
|
-
"@dxos/ui-theme": "0.
|
|
61
|
+
"vite": "^8.3.4",
|
|
62
|
+
"@dxos/random": "0.16.0",
|
|
63
|
+
"@dxos/react-ui": "0.16.0",
|
|
64
|
+
"@dxos/schema": "0.16.0",
|
|
65
|
+
"@dxos/ui-theme": "0.16.0"
|
|
65
66
|
},
|
|
66
67
|
"peerDependencies": {
|
|
67
68
|
"react": "~19.2.7",
|
|
68
69
|
"react-dom": "~19.2.7",
|
|
69
|
-
"@dxos/react-ui": "^0.
|
|
70
|
-
"@dxos/ui-theme": "^0.
|
|
70
|
+
"@dxos/react-ui": "^0.16.0",
|
|
71
|
+
"@dxos/ui-theme": "^0.16.0"
|
|
71
72
|
},
|
|
72
73
|
"publishConfig": {
|
|
73
74
|
"access": "public"
|
package/src/Message/Message.tsx
CHANGED
|
@@ -17,6 +17,7 @@ import React, {
|
|
|
17
17
|
} from 'react';
|
|
18
18
|
|
|
19
19
|
import { Obj, Ref } from '@dxos/echo';
|
|
20
|
+
import { useObject } from '@dxos/echo-react';
|
|
20
21
|
import { type UseTextEditorProps, useTextEditor } from '@dxos/react-ui-editor';
|
|
21
22
|
import * as Avatar from '@dxos/react-ui/Avatar';
|
|
22
23
|
import * as Button from '@dxos/react-ui/Button';
|
|
@@ -157,18 +158,19 @@ export type MessageBodyProps = {
|
|
|
157
158
|
*/
|
|
158
159
|
const MessageBody = ({ message, isAuthor, editing, onSave }: MessageBodyProps) => {
|
|
159
160
|
const { components } = useThreadContext('Message.Body');
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
const
|
|
161
|
+
const [{ blocks }] = useObject(message);
|
|
162
|
+
const textBlockIndex = blocks.findIndex((block) => block._tag === 'text');
|
|
163
|
+
const textBlock = textBlockIndex !== -1 ? (blocks[textBlockIndex] as ContentBlock.Text) : undefined;
|
|
164
|
+
const proposalBlock = blocks.find((block) => block._tag === 'proposal') as ContentBlock.Proposal | undefined;
|
|
165
|
+
const changeBlock = blocks.find((block) => block._tag === 'change') as ContentBlock.Change | undefined;
|
|
166
|
+
const references = blocks
|
|
165
167
|
.filter((block) => block._tag === 'reference')
|
|
166
168
|
.map((block) => (block as ContentBlock.Reference).reference);
|
|
167
169
|
const Object = components.Object;
|
|
168
170
|
|
|
169
171
|
return (
|
|
170
172
|
<>
|
|
171
|
-
{textBlock && <TextBlock
|
|
173
|
+
{textBlock && <TextBlock text={textBlock.text} isAuthor={isAuthor} editing={editing} onSave={onSave} />}
|
|
172
174
|
{proposalBlock && <div className='me-4 italic'>{proposalBlock.text}</div>}
|
|
173
175
|
{changeBlock && (
|
|
174
176
|
<p className='me-4 text-sm break-words'>
|
|
@@ -188,18 +190,18 @@ const MessageBody = ({ message, isAuthor, editing, onSave }: MessageBodyProps) =
|
|
|
188
190
|
MessageBody.displayName = 'Message.Body';
|
|
189
191
|
|
|
190
192
|
const TextBlock = ({
|
|
191
|
-
|
|
193
|
+
text,
|
|
192
194
|
isAuthor,
|
|
193
195
|
editing,
|
|
194
196
|
onSave,
|
|
195
197
|
}: {
|
|
196
|
-
|
|
198
|
+
text: string;
|
|
197
199
|
isAuthor?: boolean;
|
|
198
200
|
editing?: boolean;
|
|
199
201
|
onSave?: (text: string) => void;
|
|
200
202
|
}) => {
|
|
201
203
|
const themeMode = Hooks.useThemeMode();
|
|
202
|
-
const inMemoryContentRef = useRef(
|
|
204
|
+
const inMemoryContentRef = useRef(text);
|
|
203
205
|
|
|
204
206
|
const handleDocumentChange = useCallback((next: string) => {
|
|
205
207
|
inMemoryContentRef.current = next;
|
|
@@ -213,7 +215,7 @@ const TextBlock = ({
|
|
|
213
215
|
|
|
214
216
|
const { parentRef, focusAttributes, view } = useTextEditor(
|
|
215
217
|
() => ({
|
|
216
|
-
initialValue:
|
|
218
|
+
initialValue: text,
|
|
217
219
|
extensions: [
|
|
218
220
|
// Edit mode is authorisation enough — the control that gets here is already gated on
|
|
219
221
|
// `isAuthor` — and a mid-edit flip to read-only makes the editor drop input silently.
|
|
@@ -228,9 +230,9 @@ const TextBlock = ({
|
|
|
228
230
|
],
|
|
229
231
|
}),
|
|
230
232
|
// While editing, the editor owns its content and its authorisation: pinning both keeps an incoming
|
|
231
|
-
// `
|
|
233
|
+
// `text` update or member-list refresh from rebuilding the view being typed in. `editing` is
|
|
232
234
|
// itself a dep, so the flip still rebuilds.
|
|
233
|
-
[editing, editing ? undefined :
|
|
235
|
+
[editing, editing ? undefined : text, editing ? undefined : isAuthor, themeMode, handleDocumentChange],
|
|
234
236
|
);
|
|
235
237
|
|
|
236
238
|
useEffect(() => {
|
|
@@ -367,10 +369,11 @@ const MessageTile = ({ message, classNames, continues = true }: MessageTileProps
|
|
|
367
369
|
} = useThreadContext('Message.Tile');
|
|
368
370
|
const [editing, setEditing] = useState(false);
|
|
369
371
|
|
|
372
|
+
const [blocks] = useObject(message, 'blocks');
|
|
370
373
|
const metadata = getMetadata(message);
|
|
371
374
|
const isAuthor = !!identityDid && identityDid === metadata.authorId;
|
|
372
|
-
const hasProposal =
|
|
373
|
-
const hasChange =
|
|
375
|
+
const hasProposal = blocks.some((block) => block._tag === 'proposal');
|
|
376
|
+
const hasChange = blocks.some((block) => block._tag === 'change');
|
|
374
377
|
|
|
375
378
|
const handleEdit = useCallback(() => setEditing((value) => !value), []);
|
|
376
379
|
const handleDelete = useCallback(() => onMessageDelete?.(message.id), [onMessageDelete, message.id]);
|
|
@@ -507,9 +510,10 @@ const MessageGroup = ({ messages, continues = true, classNames }: MessageGroupPr
|
|
|
507
510
|
const [editing, setEditing] = useState(false);
|
|
508
511
|
|
|
509
512
|
const first = messages[0];
|
|
513
|
+
const [blocks] = useObject(first, 'blocks');
|
|
510
514
|
const metadata = getMetadata(first);
|
|
511
515
|
const isAuthor = !!identityDid && identityDid === metadata.authorId;
|
|
512
|
-
const hasProposal =
|
|
516
|
+
const hasProposal = blocks.some((block) => block._tag === 'proposal');
|
|
513
517
|
|
|
514
518
|
const handleEdit = useCallback(() => setEditing((value) => !value), []);
|
|
515
519
|
const handleDelete = useCallback(() => onMessageDelete?.(first.id), [onMessageDelete, first.id]);
|