@dxos/react-ui-thread 0.8.4-main.70d3990 → 0.8.4-main.74a063c4e0

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,12 +1,16 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-thread",
3
- "version": "0.8.4-main.70d3990",
3
+ "version": "0.8.4-main.74a063c4e0",
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",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
7
11
  "license": "MIT",
8
12
  "author": "DXOS.org",
9
- "sideEffects": true,
13
+ "sideEffects": false,
10
14
  "type": "module",
11
15
  "exports": {
12
16
  ".": {
@@ -24,33 +28,32 @@
24
28
  "src"
25
29
  ],
26
30
  "dependencies": {
27
- "@preact-signals/safe-react": "^0.9.0",
28
31
  "@radix-ui/react-primitive": "2.0.2",
29
- "date-fns": "^3.3.1",
30
- "@dxos/react-ui-editor": "0.8.4-main.70d3990",
31
- "@dxos/util": "0.8.4-main.70d3990"
32
+ "date-fns": "^3.6.0",
33
+ "@dxos/react-ui-editor": "0.8.4-main.74a063c4e0",
34
+ "@dxos/ui-editor": "0.8.4-main.74a063c4e0",
35
+ "@dxos/util": "0.8.4-main.74a063c4e0"
32
36
  },
33
37
  "devDependencies": {
34
- "@types/react": "~19.2.2",
35
- "@types/react-dom": "~19.2.2",
36
- "react": "~19.2.0",
37
- "react-dom": "~19.2.0",
38
- "vite": "7.1.9",
39
- "@dxos/echo": "0.8.4-main.70d3990",
40
- "@dxos/keys": "0.8.4-main.70d3990",
41
- "@dxos/live-object": "0.8.4-main.70d3990",
42
- "@dxos/echo-db": "0.8.4-main.70d3990",
43
- "@dxos/log": "0.8.4-main.70d3990",
44
- "@dxos/random": "0.8.4-main.70d3990",
45
- "@dxos/react-ui": "0.8.4-main.70d3990",
46
- "@dxos/storybook-utils": "0.8.4-main.70d3990",
47
- "@dxos/react-ui-theme": "0.8.4-main.70d3990"
38
+ "@types/react": "~19.2.7",
39
+ "@types/react-dom": "~19.2.3",
40
+ "react": "~19.2.3",
41
+ "react-dom": "~19.2.3",
42
+ "vite": "^7.1.11",
43
+ "@dxos/echo": "0.8.4-main.74a063c4e0",
44
+ "@dxos/keys": "0.8.4-main.74a063c4e0",
45
+ "@dxos/log": "0.8.4-main.74a063c4e0",
46
+ "@dxos/echo-db": "0.8.4-main.74a063c4e0",
47
+ "@dxos/random": "0.8.4-main.74a063c4e0",
48
+ "@dxos/react-ui": "0.8.4-main.74a063c4e0",
49
+ "@dxos/storybook-utils": "0.8.4-main.74a063c4e0",
50
+ "@dxos/ui-theme": "0.8.4-main.74a063c4e0"
48
51
  },
49
52
  "peerDependencies": {
50
- "react": "^19.0.0",
51
- "react-dom": "^19.0.0",
52
- "@dxos/react-ui": "0.8.4-main.70d3990",
53
- "@dxos/react-ui-theme": "0.8.4-main.70d3990"
53
+ "react": "~19.2.3",
54
+ "react-dom": "~19.2.3",
55
+ "@dxos/react-ui": "0.8.4-main.74a063c4e0",
56
+ "@dxos/ui-theme": "0.8.4-main.74a063c4e0"
54
57
  },
55
58
  "publishConfig": {
56
59
  "access": "public"
@@ -6,13 +6,12 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useState } from 'react';
7
7
 
8
8
  import { PublicKey } from '@dxos/keys';
9
- import { withTheme } from '@dxos/react-ui/testing';
10
- import { hoverableControls, hoverableFocusedWithinControls } from '@dxos/react-ui-theme';
9
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
10
+ import { hoverableControls, hoverableFocusedWithinControls } from '@dxos/ui-theme';
11
11
 
12
12
  import { type MessageEntity, MessageStoryText } from '../testing';
13
13
  import { Thread } from '../Thread';
14
14
  import { translations } from '../translations';
15
-
16
15
  import { MessageRoot } from './Message';
17
16
 
18
17
  const DefaultStory = () => {
@@ -25,7 +24,7 @@ const DefaultStory = () => {
25
24
  });
26
25
 
27
26
  return (
28
- <div className='mli-auto is-96 overflow-y-auto'>
27
+ <div className='mx-auto w-96 overflow-y-auto'>
29
28
  <Thread.Root id='t1'>
30
29
  <MessageRoot {...message} classNames={[hoverableControls, hoverableFocusedWithinControls]}>
31
30
  <MessageStoryText {...message} onDelete={() => console.log('delete')} />
@@ -39,7 +38,7 @@ const meta = {
39
38
  title: 'ui/react-ui-thread/Message',
40
39
  component: MessageRoot as any,
41
40
  render: DefaultStory,
42
- decorators: [withTheme],
41
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
43
42
  parameters: {
44
43
  layout: 'fullscreen',
45
44
  translations,
@@ -5,10 +5,10 @@
5
5
  import { formatDistanceToNow } from 'date-fns/formatDistanceToNow';
6
6
  import React, { type ComponentPropsWithRef, type ComponentPropsWithoutRef, forwardRef } from 'react';
7
7
 
8
- // TODO(burdon): Remove dep.
9
8
  import { Avatar, type ThemedClassName, useTranslation } from '@dxos/react-ui';
10
- import { type UseTextEditorProps, keymap, listener, useTextEditor } from '@dxos/react-ui-editor';
11
- import { focusRing, mx } from '@dxos/react-ui-theme';
9
+ import { type UseTextEditorProps, useTextEditor } from '@dxos/react-ui-editor';
10
+ import { keymap, listener } from '@dxos/ui-editor';
11
+ import { mx } from '@dxos/ui-theme';
12
12
  import { hexToEmoji, hexToHue, isTruthy } from '@dxos/util';
13
13
 
14
14
  import { translationKey } from '../translations';
@@ -16,9 +16,9 @@ import { type MessageMetadata } from '../types';
16
16
 
17
17
  const avatarSize = 7;
18
18
 
19
- export type MessageRootProps = ThemedClassName<ComponentPropsWithRef<'div'>> &
20
- MessageMetadata &
21
- Partial<{ continues: boolean }>;
19
+ export type MessageRootProps = ThemedClassName<
20
+ ComponentPropsWithRef<'div'> & MessageMetadata & Partial<{ continues: boolean }>
21
+ >;
22
22
 
23
23
  // TODO(burdon): Show authorName on tooltip.
24
24
  export const MessageRoot = forwardRef<HTMLDivElement, MessageRootProps>(
@@ -36,16 +36,16 @@ export const MessageRoot = forwardRef<HTMLDivElement, MessageRootProps>(
36
36
  className={mx('grid grid-cols-subgrid col-span-2', classNames)}
37
37
  ref={forwardedRef}
38
38
  >
39
- <div role='none' className='flex flex-col items-center gap-2 pbs-1'>
39
+ <div role='none' className='flex flex-col items-center gap-2 pt-1'>
40
40
  <Avatar.Content
41
41
  size={avatarSize}
42
42
  hue={authorAvatarProps?.hue || hexToHue(authorId ?? '0')}
43
43
  fallback={authorAvatarProps?.emoji || hexToEmoji(authorId ?? '0')}
44
44
  {...(authorImgSrc && { imgSrc: authorImgSrc })}
45
45
  />
46
- {continues && <div role='none' className='is-px grow bg-separator' />}
46
+ {continues && <div role='none' className='w-px grow bg-separator' />}
47
47
  </div>
48
- <div role='none' className='plb-1 min-is-0'>
48
+ <div role='none' className='py-1 min-w-0'>
49
49
  {children}
50
50
  </div>
51
51
  </div>
@@ -74,7 +74,7 @@ export type MessageAuthorNameProps = Pick<MessageMetadata, 'authorName'>;
74
74
  export const MessageAuthorName = ({ authorName }: MessageAuthorNameProps) => {
75
75
  const { t } = useTranslation(translationKey);
76
76
  return (
77
- <Avatar.Label classNames='block truncate text-sm text-subdued'>{authorName ?? t('anonymous label')}</Avatar.Label>
77
+ <Avatar.Label classNames='block truncate text-sm text-subdued'>{authorName ?? t('anonymous.label')}</Avatar.Label>
78
78
  );
79
79
  };
80
80
 
@@ -84,7 +84,7 @@ export const MessageTime = ({ timestamp }: MessageTimeProps) => {
84
84
  const { dtLocale } = useTranslation(translationKey);
85
85
  const dt = timestamp ? new Date(timestamp) : undefined;
86
86
  return (
87
- <time className='block text-subdued text-xs pbe-0.5' dateTime={dt?.toISOString()}>
87
+ <time className='block text-subdued text-xs pb-0.5' dateTime={dt?.toISOString()}>
88
88
  {dt ? formatDistanceToNow(dt, { locale: dtLocale, addSuffix: true }) : ''}
89
89
  </time>
90
90
  );
@@ -167,7 +167,7 @@ export const MessageTextbox = ({
167
167
  <div
168
168
  role='none'
169
169
  ref={parentRef}
170
- className={mx('plb-0.5 mie-1 rounded-sm', focusRing, disabled && 'opacity-50')}
170
+ className={mx('py-0.5 me-1 rounded-xs dx-focus-ring', disabled && 'opacity-50')}
171
171
  {...focusAttributes}
172
172
  />
173
173
  </MessageRoot>
@@ -5,44 +5,63 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { type FC, useEffect, useMemo, useRef, useState } from 'react';
7
7
 
8
- import { Expando } from '@dxos/echo/internal';
8
+ import { Obj } from '@dxos/echo';
9
+ import { TestSchema } from '@dxos/echo/testing';
9
10
  import { PublicKey } from '@dxos/keys';
10
11
  import { log } from '@dxos/log';
11
- import { faker } from '@dxos/random';
12
+ import { random } from '@dxos/random';
12
13
  import { Icon, IconButton, useThemeContext } from '@dxos/react-ui';
13
- import { withTheme } from '@dxos/react-ui/testing';
14
+ import { useTextEditor } from '@dxos/react-ui-editor';
15
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
14
16
  import {
15
17
  type Comment,
16
18
  type CommentsOptions,
19
+ type EditorView,
17
20
  type Range,
18
21
  comments,
19
22
  createBasicExtensions,
20
23
  createThemeExtensions,
24
+ documentId,
21
25
  listener,
22
26
  scrollThreadIntoView,
23
- useComments,
24
- useTextEditor,
25
- } from '@dxos/react-ui-editor';
26
- import { hoverableControls, hoverableFocusedWithinControls } from '@dxos/react-ui-theme';
27
+ setComments,
28
+ } from '@dxos/ui-editor';
29
+ import { hoverableControls, hoverableFocusedWithinControls } from '@dxos/ui-theme';
27
30
 
28
- import { Obj } from '../../../../core/echo/echo/src';
29
31
  import { MessageBody, MessageHeading, MessageRoot, MessageTextbox } from '../Message';
30
32
  import { type MessageEntity } from '../testing';
31
33
  import { translations } from '../translations';
32
-
33
34
  import { Thread } from './Thread';
34
35
 
35
- faker.seed(101);
36
+ random.seed(101);
36
37
 
37
38
  const authorId = PublicKey.random().toHex();
38
39
 
40
+ /**
41
+ * @deprecated This hook will be removed in future versions. Use the new comment sync extension instead.
42
+ * Update comments state field.
43
+ */
44
+ const useComments = (view: EditorView | null | undefined, id: string, comments?: Comment[]) => {
45
+ useEffect(() => {
46
+ if (view) {
47
+ // Check same document.
48
+ // NOTE: Hook might be called before editor state is updated.
49
+ if (id === view.state.facet(documentId)) {
50
+ view.dispatch({
51
+ effects: setComments.of({ id, comments: comments ?? [] }),
52
+ });
53
+ }
54
+ }
55
+ });
56
+ };
57
+
39
58
  //
40
59
  // Editor
41
60
  //
42
61
 
43
62
  const Editor: FC<{
44
63
  id?: string;
45
- item: Expando;
64
+ initialValue: string;
46
65
  comments: Comment[];
47
66
  selected?: string;
48
67
  onCreateComment: CommentsOptions['onCreate'];
@@ -51,7 +70,7 @@ const Editor: FC<{
51
70
  onSelectComment: CommentsOptions['onSelect'];
52
71
  }> = ({
53
72
  id = 'test',
54
- item,
73
+ initialValue,
55
74
  selected: selectedValue,
56
75
  comments: commentRanges,
57
76
  onCreateComment,
@@ -65,7 +84,7 @@ const Editor: FC<{
65
84
  const { parentRef, view } = useTextEditor(
66
85
  () => ({
67
86
  id,
68
- initialValue: item.content,
87
+ initialValue: initialValue,
69
88
  extensions: [
70
89
  createBasicExtensions(),
71
90
  createThemeExtensions({ themeMode }),
@@ -78,7 +97,7 @@ const Editor: FC<{
78
97
  }),
79
98
  ],
80
99
  }),
81
- [id, item, themeMode],
100
+ [id, initialValue, themeMode],
82
101
  );
83
102
  useComments(view, id, commentRanges);
84
103
  useEffect(() => {
@@ -141,7 +160,7 @@ const StoryThread: FC<{
141
160
 
142
161
  const handleCreateMessage = () => {
143
162
  if (messageRef.current?.length) {
144
- const message = Obj.make(Expando, {
163
+ const message = Obj.make(TestSchema.Expando, {
145
164
  timestamp: new Date().toISOString(),
146
165
  sender: { identityKey: authorId },
147
166
  text: messageRef.current,
@@ -188,7 +207,7 @@ const StoryThread: FC<{
188
207
  variant='ghost'
189
208
  icon='ph--check--regular'
190
209
  iconOnly
191
- classNames='pli-1'
210
+ classNames='px-1'
192
211
  label='Resolve'
193
212
  onClick={onResolve}
194
213
  />
@@ -197,12 +216,14 @@ const StoryThread: FC<{
197
216
  );
198
217
  };
199
218
 
200
- const Sidebar: FC<{
219
+ type SidebarProps = {
201
220
  threads: StoryCommentThread[];
202
221
  selected?: string;
203
222
  onSelect: (thread: string) => void;
204
223
  onResolve: (thread: string) => void;
205
- }> = ({ threads, selected, onSelect, onResolve }) => {
224
+ };
225
+
226
+ const Sidebar = ({ threads, selected, onSelect, onResolve }: SidebarProps) => {
206
227
  // Sort by y-position.
207
228
  const sortedThreads = useMemo(() => {
208
229
  const sorted = [...threads];
@@ -230,13 +251,13 @@ const Sidebar: FC<{
230
251
  // Story container.
231
252
  //
232
253
 
233
- type StoryProps = {
254
+ type DefaultStoryProps = {
234
255
  text?: string;
235
256
  autoCreate?: boolean;
236
257
  };
237
258
 
238
- const DefaultStory = ({ text, autoCreate }: StoryProps) => {
239
- const [item] = useState(() => Obj.make(Expando, { content: text ?? '' }));
259
+ const DefaultStory = ({ text, autoCreate }: DefaultStoryProps) => {
260
+ const [item] = useState(() => Obj.make(TestSchema.Expando, { content: text ?? '' }));
240
261
  const [threads, setThreads] = useState<StoryCommentThread[]>([]);
241
262
  const [selected, setSelected] = useState<string>();
242
263
 
@@ -255,12 +276,12 @@ const DefaultStory = ({ text, autoCreate }: StoryProps) => {
255
276
  cursor,
256
277
  yPos: location ? Math.floor(location.top) : undefined,
257
278
  messages: autoCreate
258
- ? faker.helpers.multiple(
279
+ ? random.helpers.multiple(
259
280
  () => ({
260
281
  id: PublicKey.random().toHex(),
261
282
  timestamp: new Date().toISOString(),
262
283
  authorId: PublicKey.random().toHex(),
263
- text: faker.lorem.sentence(),
284
+ text: random.lorem.sentence(),
264
285
  }),
265
286
  { count: { min: 1, max: 3 } },
266
287
  )
@@ -328,9 +349,9 @@ const DefaultStory = ({ text, autoCreate }: StoryProps) => {
328
349
 
329
350
  return (
330
351
  <main className='fixed inset-0 grid grid-cols-[1fr_24rem]'>
331
- <div role='none' className='max-bs-full overflow-y-auto p-4'>
352
+ <div role='none' className='max-h-full overflow-y-auto p-4'>
332
353
  <Editor
333
- item={item}
354
+ initialValue={item.content}
334
355
  selected={selected}
335
356
  comments={comments}
336
357
  onCreateComment={handleCreateComment}
@@ -340,7 +361,7 @@ const DefaultStory = ({ text, autoCreate }: StoryProps) => {
340
361
  />
341
362
  </div>
342
363
 
343
- <div role='none' className='max-bs-full overflow-y-auto p-4'>
364
+ <div role='none' className='max-h-full overflow-y-auto p-4'>
344
365
  <Sidebar
345
366
  threads={visibleThreads}
346
367
  selected={selected}
@@ -356,7 +377,7 @@ const meta = {
356
377
  title: 'ui/react-ui-thread/Comments',
357
378
  component: StoryThread as any,
358
379
  render: DefaultStory,
359
- decorators: [withTheme],
380
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
360
381
  parameters: {
361
382
  translations,
362
383
  layout: 'fullscreen',
@@ -374,7 +395,7 @@ export const Default: Story = {
374
395
  text: str(
375
396
  '# Comments',
376
397
  '',
377
- str(...faker.helpers.multiple(() => [faker.lorem.paragraph({ min: 5, max: 10 }), ''], { count: 20 }).flat()),
398
+ str(...random.helpers.multiple(() => [random.lorem.paragraph({ min: 5, max: 10 }), ''], { count: 20 }).flat()),
378
399
  '',
379
400
  ),
380
401
  },
@@ -6,18 +6,17 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useMemo, useRef, useState } from 'react';
7
7
 
8
8
  import { PublicKey } from '@dxos/keys';
9
- import { faker } from '@dxos/random';
10
- import { withTheme } from '@dxos/react-ui/testing';
11
- import { createBasicExtensions, createThemeExtensions } from '@dxos/react-ui-editor';
12
- import { hoverableControls, hoverableFocusedWithinControls } from '@dxos/react-ui-theme';
9
+ import { random } from '@dxos/random';
10
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
+ import { createBasicExtensions, createThemeExtensions } from '@dxos/ui-editor';
12
+ import { hoverableControls, hoverableFocusedWithinControls } from '@dxos/ui-theme';
13
13
 
14
14
  import { MessageRoot, MessageTextbox } from '../Message';
15
15
  import { type MessageEntity, MessageStoryText } from '../testing';
16
16
  import { translations } from '../translations';
17
-
18
17
  import { Thread } from './Thread';
19
18
 
20
- faker.seed(1);
19
+ random.seed(1);
21
20
 
22
21
  const DefaultStory = () => {
23
22
  const [pending, setPending] = useState(false);
@@ -28,7 +27,7 @@ const DefaultStory = () => {
28
27
  id: `m${i + 1}`,
29
28
  timestamp: new Date().toISOString(),
30
29
  authorId: [identityKey1.toHex(), identityKey2.toHex()][i % 2],
31
- text: faker.lorem.paragraph(),
30
+ text: random.lorem.paragraph(),
32
31
  })),
33
32
  );
34
33
 
@@ -59,7 +58,7 @@ const DefaultStory = () => {
59
58
  };
60
59
 
61
60
  return (
62
- <div className='mli-auto is-96 overflow-y-auto'>
61
+ <div className='mx-auto w-96 overflow-y-auto'>
63
62
  <Thread.Root id='t1'>
64
63
  {messages.map((message) => (
65
64
  <MessageRoot key={message.id} classNames={[hoverableControls, hoverableFocusedWithinControls]} {...message}>
@@ -85,7 +84,7 @@ const meta = {
85
84
  title: 'ui/react-ui-thread/Thread',
86
85
  component: Thread.Root,
87
86
  render: DefaultStory,
88
- decorators: [withTheme],
87
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
89
88
  parameters: {
90
89
  layout: 'fullscreen',
91
90
  translations,
@@ -2,22 +2,26 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import React, { type ComponentPropsWithRef, forwardRef } from 'react';
5
+ import React, { ComponentPropsWithRef, forwardRef, PropsWithChildren } from 'react';
6
6
 
7
7
  import { Icon, type ThemedClassName, useTranslation } from '@dxos/react-ui';
8
- import { hoverableControlItem, hoverableFocusedWithinControls, mx } from '@dxos/react-ui-theme';
8
+ import { hoverableControlItem, hoverableFocusedWithinControls, mx } from '@dxos/ui-theme';
9
9
 
10
10
  import { translationKey } from '../translations';
11
11
  import type { ThreadEntity } from '../types';
12
12
 
13
- // TODO(burdon): Why is this exported?
14
- export const threadLayout = 'is-full place-self-start grid grid-cols-[var(--rail-size)_1fr]';
13
+ // TODO(burdon): Avoid exporting fragments.
14
+ export const threadLayout = 'w-full place-self-start grid grid-cols-[var(--dx-rail-size)_1fr]';
15
15
 
16
16
  //
17
17
  // Root
18
18
  //
19
19
 
20
- type ThreadRootProps = ThemedClassName<ComponentPropsWithRef<'div'>> & ThreadEntity & { current?: boolean };
20
+ type ThreadRootProps = ThemedClassName<
21
+ PropsWithChildren<
22
+ ThreadEntity & { current?: boolean } & Pick<ComponentPropsWithRef<'div'>, 'onClickCapture' | 'onFocusCapture'>
23
+ >
24
+ >;
21
25
 
22
26
  const ThreadRoot = forwardRef<HTMLDivElement, ThreadRootProps>(
23
27
  ({ current, children, classNames, ...props }, forwardedRef) => {
@@ -30,7 +34,7 @@ const ThreadRoot = forwardRef<HTMLDivElement, ThreadRootProps>(
30
34
  className={mx(
31
35
  threadLayout,
32
36
  hoverableFocusedWithinControls,
33
- 'bg-[var(--surface-bg)] current-related attention-surface [--controls-opacity:0]',
37
+ 'bg-[var(--surface-bg)] current-related dx-attention-surface [--controls-opacity:0]',
34
38
  classNames,
35
39
  )}
36
40
  ref={forwardedRef}
@@ -45,7 +49,7 @@ const ThreadRoot = forwardRef<HTMLDivElement, ThreadRootProps>(
45
49
  // Heading
46
50
  //
47
51
 
48
- type ThreadHeaderProps = ComponentPropsWithRef<'div'> & { detached?: boolean };
52
+ type ThreadHeaderProps = PropsWithChildren<{ detached?: boolean }>;
49
53
 
50
54
  const ThreadHeader = forwardRef<HTMLParagraphElement, ThreadHeaderProps>(
51
55
  ({ children, detached, ...props }, forwardedRef) => {
@@ -59,10 +63,7 @@ const ThreadHeader = forwardRef<HTMLParagraphElement, ThreadHeaderProps>(
59
63
  role='heading'
60
64
  data-testid='thread.heading'
61
65
  {...props}
62
- className={mx(
63
- 'mie-2 text-description font-medium truncate italic',
64
- detached && 'line-through decoration-1',
65
- )}
66
+ className={mx('me-2 text-description font-medium truncate italic', detached && 'line-through decoration-1')}
66
67
  ref={forwardedRef}
67
68
  >
68
69
  {children}
@@ -77,7 +78,7 @@ const ThreadHeader = forwardRef<HTMLParagraphElement, ThreadHeaderProps>(
77
78
  // Status
78
79
  //
79
80
 
80
- type ThreadStatusProps = ThemedClassName<ComponentPropsWithRef<'div'>> & {
81
+ type ThreadStatusProps = ThemedClassName<PropsWithChildren> & {
81
82
  activity?: boolean;
82
83
  };
83
84
 
@@ -88,20 +89,20 @@ const ThreadStatus = forwardRef<HTMLDivElement, ThreadStatusProps>(
88
89
  <div
89
90
  {...props}
90
91
  className={mx(
91
- 'col-start-2 grid grid-cols-[min-content_1fr_max-content] pb-2 pie-2 text-xs text-description',
92
+ 'col-start-2 grid grid-cols-[min-content_1fr_max-content] pb-2 pe-2 text-xs text-description',
92
93
  classNames,
93
94
  )}
94
95
  ref={forwardedRef}
95
96
  >
96
97
  <Icon
97
98
  icon='ph--spinner--bold'
98
- classNames='is-6 bs-4 invisible data-[visible=show]:visible animate-spin-slow'
99
+ classNames='w-6 h-4 invisible data-[visible=show]:visible animate-spin-slow'
99
100
  data-visible={activity ? 'show' : 'hide'}
100
101
  />
101
- <span className='truncate min-is-0' aria-live='polite'>
102
+ <span className='truncate min-w-0' aria-live='polite'>
102
103
  {activity ? children : null}
103
104
  </span>
104
- <span className={mx('text-end', hoverableControlItem)}>{t('enter to send message')}</span>
105
+ <span className={mx('text-end', hoverableControlItem)}>{t('enter-to-send.message')}</span>
105
106
  </div>
106
107
  );
107
108
  },
@@ -113,4 +114,4 @@ export const Thread = {
113
114
  Status: ThreadStatus,
114
115
  };
115
116
 
116
- export type { ThreadRootProps, ThreadHeaderProps as ThreadHeadingProps, ThreadStatusProps };
117
+ export type { ThreadRootProps, ThreadHeaderProps, ThreadStatusProps };
package/src/testing.tsx CHANGED
@@ -5,7 +5,7 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { IconButton } from '@dxos/react-ui';
8
- import { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx } from '@dxos/react-ui-theme';
8
+ import { hoverableControlItem, hoverableControls, hoverableFocusedWithinControls, mx } from '@dxos/ui-theme';
9
9
 
10
10
  import { MessageBody, MessageHeading } from './Message';
11
11
  import { type MessageMetadata } from './types';
@@ -30,7 +30,7 @@ export const MessageStoryText = ({ text, onDelete, authorName, timestamp }: Mess
30
30
  iconOnly
31
31
  label='Delete'
32
32
  variant='ghost'
33
- classNames={['p-1.5 min-bs-0 mie-1 items-start transition-opacity', hoverableControlItem]}
33
+ classNames={['p-1.5 min-h-0 me-1 items-start transition-opacity', hoverableControlItem]}
34
34
  onClick={() => onDelete()}
35
35
  />
36
36
  )}
@@ -50,7 +50,7 @@ export const MessageStoryBlock = <PartValue,>({ part }: MessagePartProps<PartVal
50
50
  role='none'
51
51
  className={mx('grid grid-cols-subgrid col-span-3', hoverableControls, hoverableFocusedWithinControls)}
52
52
  >
53
- <pre className='font-mono max-is-full overflow-x-auto col-span-3'>
53
+ <pre className='font-mono max-w-full overflow-x-auto col-span-3'>
54
54
  <code>{JSON.stringify(part, undefined, 2)}</code>
55
55
  </pre>
56
56
  </div>
@@ -4,22 +4,22 @@
4
4
 
5
5
  import { type Resource } from '@dxos/react-ui';
6
6
 
7
- export const translationKey = 'react-ui-thread';
7
+ export const translationKey = '@dxos/react-ui-thread';
8
8
 
9
9
  export const translations = [
10
10
  {
11
11
  'en-US': {
12
12
  [translationKey]: {
13
- 'plugin name': 'Threads',
14
- 'thread title placeholder': 'New thread',
15
- 'thread title label': 'Title',
16
- 'delete thread label': 'Delete',
17
- 'create thread label': 'Create thread',
18
- 'message placeholder': 'Enter message...',
19
- 'comment placeholder': 'Enter comment...',
20
- 'settings standalone label': 'Enable standalone thread creation',
21
- 'anonymous label': 'Anonymous',
22
- 'enter to send message': 'Enter to add ⏎',
13
+ 'plugin.name': 'Threads',
14
+ 'thread-title.placeholder': 'New thread',
15
+ 'thread-title.label': 'Title',
16
+ 'delete-thread.label': 'Delete',
17
+ 'create-thread.label': 'Create thread',
18
+ 'message.placeholder': 'Enter message...',
19
+ 'comment.placeholder': 'Enter comment...',
20
+ 'settings-standalone.label': 'Enable standalone thread creation',
21
+ 'anonymous.label': 'Anonymous',
22
+ 'enter-to-send.message': 'Enter to add ⏎',
23
23
  },
24
24
  },
25
25
  },
package/src/types.ts CHANGED
@@ -16,6 +16,7 @@ export type MessageMetadata = {
16
16
  };
17
17
 
18
18
  export type ThreadEntity = {
19
+ id?: string;
19
20
  topicId?: string;
20
21
  topicTitle?: string;
21
22
  };