@dxos/react-ui-thread 0.4.8-main.0602afb → 0.4.8-main.2d8e727

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.
@@ -72,10 +72,11 @@ import { X } from "@phosphor-icons/react";
72
72
  import { formatDistanceToNow } from "date-fns/formatDistanceToNow";
73
73
  import React2, { forwardRef as forwardRef2, useMemo } from "react";
74
74
  import { Avatar, Button, useTranslation as useTranslation2 } from "@dxos/react-ui";
75
- import { keymap, listener, TextEditor } from "@dxos/react-ui-editor";
75
+ import { TextEditor, keymap, listener } from "@dxos/react-ui-editor";
76
76
  import { focusRing, hoverableControlItem as hoverableControlItem2, hoverableControls, hoverableFocusedWithinControls as hoverableFocusedWithinControls2, mx as mx2 } from "@dxos/react-ui-theme";
77
- import { safeParseJson, hexToEmoji, hexToHue, isNotFalsy } from "@dxos/util";
77
+ import { safeParseJson, hexToEmoji, hexToHue } from "@dxos/util";
78
78
  var avatarSize = 7;
79
+ var messageCell = "plb-1 min-is-0";
79
80
  var MessageMeta = /* @__PURE__ */ forwardRef2(({ authorImgSrc, authorId, authorName, authorAvatarProps, continues = true, children, classNames, ...rootProps }, forwardedRef) => {
80
81
  return /* @__PURE__ */ React2.createElement(Avatar.Root, {
81
82
  size: avatarSize,
@@ -88,7 +89,7 @@ var MessageMeta = /* @__PURE__ */ forwardRef2(({ authorImgSrc, authorId, authorN
88
89
  ref: forwardedRef
89
90
  }, /* @__PURE__ */ React2.createElement("div", {
90
91
  role: "none",
91
- className: mx2("flex flex-col items-center gap-2 plb-2")
92
+ className: mx2("flex flex-col items-center gap-2", messageCell)
92
93
  }, /* @__PURE__ */ React2.createElement(Avatar.Frame, null, /* @__PURE__ */ React2.createElement(Avatar.Fallback, {
93
94
  text: authorAvatarProps?.emoji || hexToEmoji(authorId ?? "0")
94
95
  }), authorImgSrc && /* @__PURE__ */ React2.createElement(Avatar.Image, {
@@ -98,7 +99,7 @@ var MessageMeta = /* @__PURE__ */ forwardRef2(({ authorImgSrc, authorId, authorN
98
99
  className: "is-px grow surface-separator"
99
100
  })), /* @__PURE__ */ React2.createElement("div", {
100
101
  role: "none",
101
- className: "plb-1 min-is-0"
102
+ className: messageCell
102
103
  }, children)));
103
104
  });
104
105
  var DefaultMessageBlock = ({ block, onBlockDelete }) => {
@@ -151,63 +152,65 @@ var Message = (props) => {
151
152
  onBlockDelete: onDelete && (() => onDelete(id, i))
152
153
  }))));
153
154
  };
154
- var keyBindings = ({ onSend, onClear }) => [
155
- {
156
- key: "Enter",
157
- run: () => {
158
- if (onSend) {
159
- onSend();
160
- return true;
161
- } else {
162
- return false;
163
- }
164
- }
165
- },
166
- {
167
- // TODO(burdon): Other key bindings.
168
- key: "Meta+Backspace",
169
- run: () => {
170
- if (onClear) {
171
- onClear();
172
- return true;
173
- } else {
174
- return false;
175
- }
176
- }
177
- }
178
- ];
179
- var MessageTextbox = ({ id, onSend, onClear, onEditorFocus, authorId, authorName, authorImgSrc, authorAvatarProps, disabled, extensions: _extensions, ...editorProps }) => {
180
- const extensions = useMemo(() => {
181
- return [
182
- _extensions,
183
- keymap.of(keyBindings({
184
- onSend,
185
- onClear
186
- })),
187
- listener({
188
- onFocus: (focusing) => {
189
- if (focusing) {
190
- onEditorFocus?.();
155
+ var MessageTextbox = /* @__PURE__ */ forwardRef2(({ onSend, onClear, onEditorFocus, authorId, authorName, authorImgSrc, authorAvatarProps, disabled, extensions: _extensions, ...editorProps }, forwardedRef) => {
156
+ const extensions = useMemo(() => [
157
+ ..._extensions ?? [],
158
+ keymap.of([
159
+ {
160
+ key: "Enter",
161
+ run: () => {
162
+ if (onSend) {
163
+ onSend();
164
+ return true;
165
+ } else {
166
+ return false;
191
167
  }
192
168
  }
193
- })
194
- ].filter(isNotFalsy);
195
- }, [
196
- _extensions
169
+ },
170
+ {
171
+ key: "Meta+Backspace",
172
+ run: () => {
173
+ if (onClear) {
174
+ onClear();
175
+ return true;
176
+ } else {
177
+ return false;
178
+ }
179
+ }
180
+ }
181
+ ]),
182
+ listener({
183
+ onFocus: (focused) => {
184
+ if (focused) {
185
+ onEditorFocus?.();
186
+ }
187
+ }
188
+ })
189
+ ], [
190
+ _extensions,
191
+ onSend,
192
+ onClear,
193
+ onEditorFocus
197
194
  ]);
198
195
  return /* @__PURE__ */ React2.createElement(MessageMeta, {
199
- id,
196
+ id: editorProps.model.id,
200
197
  authorId,
201
198
  authorName,
202
199
  authorImgSrc,
203
200
  authorAvatarProps,
204
201
  continues: false
205
202
  }, /* @__PURE__ */ React2.createElement(TextEditor, {
206
- ...editorProps,
203
+ slots: {
204
+ root: {
205
+ className: mx2("plb-0.5 mie-1 rounded-sm", focusRing, disabled && "opacity-50")
206
+ }
207
+ },
208
+ readonly: disabled,
207
209
  extensions,
208
- className: mx2("plb-0.5 mie-1 rounded-sm", focusRing, disabled && "opacity-50")
210
+ ...editorProps,
211
+ ref: forwardedRef
209
212
  }));
210
- };
213
+ });
211
214
  export {
212
215
  Message,
213
216
  MessageMeta,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/translations.ts", "../../../src/Thread/Thread.tsx", "../../../src/Message/Message.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nexport const translationKey = 'thread';\n\nexport default [\n {\n 'en-US': {\n [translationKey]: {\n 'plugin name': 'Threads',\n 'thread title placeholder': 'New thread',\n 'thread title label': 'Title',\n 'delete thread label': 'Delete',\n 'create thread label': 'Create thread',\n 'message placeholder': 'Enter message...',\n 'comment placeholder': 'Enter comment...',\n 'settings standalone label': 'Enable standalone thread creation',\n 'anonymous label': 'Anonymous',\n 'enter to send message': 'Enter to add ⏎',\n },\n },\n },\n];\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { ArrowBendLeftDown, Spinner } from '@phosphor-icons/react';\nimport React, { type ComponentProps, type ComponentPropsWithRef, forwardRef } from 'react';\n\nimport { type ThemedClassName, useTranslation } from '@dxos/react-ui';\nimport { hoverableControlItem, hoverableFocusedWithinControls, mx } from '@dxos/react-ui-theme';\n\nimport { translationKey } from '../translations';\nimport type { ThreadEntity } from '../types';\n\nexport type ThreadProps = ThemedClassName<ComponentPropsWithRef<'div'>> &\n ThreadEntity & { current?: boolean | ComponentProps<'div'>['aria-current'] };\n\nexport const threadLayout = 'is-full place-self-start grid grid-cols-[var(--rail-size)_1fr]';\n\nexport const Thread = forwardRef<HTMLDivElement, ThreadProps>(\n ({ current, children, classNames, ...props }, forwardedRef) => {\n return (\n <div\n role='group'\n data-testid='thread'\n {...(current && { 'aria-current': typeof current === 'string' ? current : 'location' })}\n {...props}\n className={mx(\n threadLayout,\n hoverableFocusedWithinControls,\n 'bg-[var(--surface-bg)] border-[color:var(--surface-separator)] border-bs border-be plb-1.5 attention attention-within attention-current [--controls-opacity:0]',\n classNames,\n )}\n ref={forwardedRef}\n >\n {children}\n </div>\n );\n },\n);\n\nexport type ThreadHeadingProps = ThemedClassName<ComponentPropsWithRef<'div'>> & { detached?: boolean };\n\nexport const ThreadHeading = forwardRef<HTMLParagraphElement, ThreadHeadingProps>(\n ({ classNames, children, detached, ...props }, forwardedRef) => {\n return (\n <>\n <div role='none' className='grid place-items-end pie-3.5 fg-description'>\n <ArrowBendLeftDown />\n </div>\n <p\n role='heading'\n data-testid='thread.heading'\n {...props}\n className={mx(\n 'fg-description font-medium truncate before:content-[open-quote] after:content-[close-quote]',\n detached && 'line-through decoration-1',\n )}\n ref={forwardedRef}\n >\n {children}\n </p>\n </>\n );\n },\n);\n\nexport type ThreadFooterProps = ThemedClassName<ComponentPropsWithRef<'div'>> & {\n activity?: boolean;\n};\n\nexport const ThreadFooter = forwardRef<HTMLDivElement, ThreadFooterProps>(\n ({ activity, classNames, children, ...props }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n return (\n <div\n {...props}\n className={mx('col-start-2 grid grid-cols-[min-content_1fr_max-content] text-xs fg-description', classNames)}\n ref={forwardedRef}\n >\n <Spinner\n weight='bold'\n data-visible={activity ? 'show' : 'hide'}\n className='is-6 bs-4 invisible data-[visible=show]:visible animate-spin-slow'\n />\n <span className='truncate min-is-0' aria-live='polite'>\n {activity ? children : null}\n </span>\n <span className={mx('text-end pie-1', hoverableControlItem)}>{t('enter to send message')}</span>\n </div>\n );\n },\n);\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { X } from '@phosphor-icons/react';\nimport { formatDistanceToNow } from 'date-fns/formatDistanceToNow';\nimport React, { type ComponentPropsWithRef, type FC, forwardRef, useMemo } from 'react';\n\n// TODO(burdon): Remove dep.\nimport { Avatar, Button, type ThemedClassName, useTranslation } from '@dxos/react-ui';\nimport { type TextEditorProps, keymap, listener, TextEditor } from '@dxos/react-ui-editor';\nimport {\n focusRing,\n hoverableControlItem,\n hoverableControls,\n hoverableFocusedWithinControls,\n mx,\n} from '@dxos/react-ui-theme';\nimport { safeParseJson, hexToEmoji, hexToHue, isNotFalsy } from '@dxos/util';\n\nimport { translationKey } from '../translations';\nimport { type MessageEntity, type MessageEntityBlock, type MessageMetadata } from '../types';\n\nconst avatarSize = 7;\n\nexport type MessageMetaProps = ThemedClassName<ComponentPropsWithRef<'div'>> &\n MessageMetadata &\n Partial<{ continues: boolean }>;\n\nexport const MessageMeta = forwardRef<HTMLDivElement, MessageMetaProps>(\n (\n { authorImgSrc, authorId, authorName, authorAvatarProps, continues = true, children, classNames, ...rootProps },\n forwardedRef,\n ) => {\n return (\n <Avatar.Root size={avatarSize} hue={authorAvatarProps?.hue || hexToHue(authorId ?? '0')}>\n <div\n role='none'\n data-testid='thread.message'\n {...rootProps}\n className={mx('grid grid-cols-subgrid col-span-2', classNames)}\n ref={forwardedRef}\n >\n <div role='none' className={mx('flex flex-col items-center gap-2 plb-2')}>\n <Avatar.Frame>\n <Avatar.Fallback text={authorAvatarProps?.emoji || hexToEmoji(authorId ?? '0')} />\n {authorImgSrc && <Avatar.Image href={authorImgSrc} />}\n </Avatar.Frame>\n {continues && <div role='none' className='is-px grow surface-separator' />}\n </div>\n <div role='none' className='plb-1 min-is-0'>\n {children}\n </div>\n </div>\n </Avatar.Root>\n );\n },\n);\n\nexport type MessageBlockProps<BlockValue> = {\n block: MessageEntityBlock<BlockValue>;\n authorId?: string;\n onBlockDelete?: () => void;\n};\n\nconst DefaultMessageBlock = ({ block, onBlockDelete }: MessageBlockProps<{ data?: any; text?: string }>) => {\n const contentWidth = onBlockDelete ? 'col-span-2' : 'col-span-3';\n return (\n <div\n role='none'\n className={mx('grid grid-cols-subgrid col-span-3', hoverableControls, hoverableFocusedWithinControls)}\n >\n {block.data ? (\n <pre className={mx('font-mono max-is-full overflow-x-auto', contentWidth)}>\n <code>{JSON.stringify(safeParseJson(block.data), undefined, 2)}</code>\n </pre>\n ) : (\n <p className={contentWidth}>{block.text ?? ''}</p>\n )}\n {onBlockDelete && (\n <Button\n variant='ghost'\n classNames={['p-1.5 min-bs-0 mie-1 items-start transition-opacity', hoverableControlItem]}\n onClick={() => onBlockDelete()}\n >\n <X />\n </Button>\n )}\n </div>\n );\n};\n\nexport type MessageProps<BlockValue> = MessageEntity<BlockValue> & {\n onDelete?: (messageId: string, blockIndex: number) => void;\n MessageBlockComponent?: FC<MessageBlockProps<BlockValue>>;\n};\n\nexport const Message = <BlockValue,>(props: MessageProps<BlockValue>) => {\n const { id, authorName, onDelete, blocks, MessageBlockComponent = DefaultMessageBlock, ...metaProps } = props;\n const { t, dtLocale } = useTranslation(translationKey);\n const firstBlock = blocks[0];\n const dt = firstBlock.timestamp ? new Date(firstBlock.timestamp) : undefined;\n\n return (\n <MessageMeta {...metaProps} id={id} continues>\n <p className='grid grid-cols-[1fr_max-content] gap-2 pie-2'>\n <Avatar.Label classNames={['truncate text-sm font-medium', !authorName && 'fg-description']}>\n {authorName ?? t('anonymous label')}\n </Avatar.Label>\n <time className='fg-description text-xs pbs-0.5' dateTime={dt?.toISOString()}>\n {dt ? formatDistanceToNow(dt, { locale: dtLocale, addSuffix: true }) : ''}\n </time>\n </p>\n <div role='none' className='grid gap-y-1 grid-cols-[min-content_1fr_min-content]'>\n {blocks.map((block, i) => (\n <MessageBlockComponent\n key={i}\n block={block}\n authorId={metaProps.authorId}\n onBlockDelete={onDelete && (() => onDelete(id, i))}\n />\n ))}\n </div>\n </MessageMeta>\n );\n};\n\nexport type MessageTextboxProps = {\n disabled?: boolean;\n onSend?: () => void;\n onClear?: () => void;\n onEditorFocus?: () => void;\n} & MessageMetadata &\n TextEditorProps;\n\nconst keyBindings = ({ onSend, onClear }: Pick<MessageTextboxProps, 'onSend' | 'onClear'>) => [\n {\n key: 'Enter',\n run: () => {\n if (onSend) {\n onSend();\n return true;\n } else {\n return false;\n }\n },\n },\n {\n // TODO(burdon): Other key bindings.\n key: 'Meta+Backspace',\n run: () => {\n if (onClear) {\n onClear();\n return true;\n } else {\n return false;\n }\n },\n },\n];\n\nexport const MessageTextbox = ({\n id,\n onSend,\n onClear,\n onEditorFocus,\n authorId,\n authorName,\n authorImgSrc,\n authorAvatarProps,\n disabled,\n extensions: _extensions,\n ...editorProps\n}: MessageTextboxProps) => {\n const extensions = useMemo<TextEditorProps['extensions']>(() => {\n return [\n _extensions,\n keymap.of(keyBindings({ onSend, onClear })),\n listener({\n onFocus: (focusing) => {\n if (focusing) {\n onEditorFocus?.();\n }\n },\n }),\n ].filter(isNotFalsy);\n }, [_extensions]);\n\n return (\n <MessageMeta {...{ id, authorId, authorName, authorImgSrc, authorAvatarProps }} continues={false}>\n <TextEditor\n {...editorProps}\n extensions={extensions}\n className={mx('plb-0.5 mie-1 rounded-sm', focusRing, disabled && 'opacity-50')}\n />\n </MessageMeta>\n );\n};\n"],
5
- "mappings": "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",
6
- "names": ["translationKey", "ArrowBendLeftDown", "Spinner", "React", "forwardRef", "useTranslation", "hoverableControlItem", "hoverableFocusedWithinControls", "mx", "threadLayout", "Thread", "forwardRef", "current", "children", "classNames", "props", "forwardedRef", "div", "role", "data-testid", "className", "mx", "hoverableFocusedWithinControls", "ref", "ThreadHeading", "detached", "ArrowBendLeftDown", "p", "ThreadFooter", "activity", "t", "useTranslation", "translationKey", "Spinner", "weight", "data-visible", "span", "aria-live", "hoverableControlItem", "X", "formatDistanceToNow", "React", "forwardRef", "useMemo", "Avatar", "Button", "useTranslation", "keymap", "listener", "TextEditor", "focusRing", "hoverableControlItem", "hoverableControls", "hoverableFocusedWithinControls", "mx", "safeParseJson", "hexToEmoji", "hexToHue", "isNotFalsy", "avatarSize", "MessageMeta", "forwardRef", "authorImgSrc", "authorId", "authorName", "authorAvatarProps", "continues", "children", "classNames", "rootProps", "forwardedRef", "React", "Avatar", "Root", "size", "hue", "hexToHue", "div", "role", "data-testid", "className", "mx", "ref", "Frame", "Fallback", "text", "emoji", "hexToEmoji", "Image", "href", "DefaultMessageBlock", "block", "onBlockDelete", "contentWidth", "hoverableControls", "hoverableFocusedWithinControls", "data", "pre", "code", "JSON", "stringify", "safeParseJson", "undefined", "p", "Button", "variant", "hoverableControlItem", "onClick", "X", "Message", "props", "id", "onDelete", "blocks", "MessageBlockComponent", "metaProps", "t", "dtLocale", "useTranslation", "translationKey", "firstBlock", "dt", "timestamp", "Date", "Label", "time", "dateTime", "toISOString", "formatDistanceToNow", "locale", "addSuffix", "map", "i", "key", "keyBindings", "onSend", "onClear", "run", "MessageTextbox", "onEditorFocus", "disabled", "extensions", "_extensions", "editorProps", "useMemo", "keymap", "of", "listener", "onFocus", "focusing", "filter", "isNotFalsy", "TextEditor", "focusRing"]
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nexport const translationKey = 'thread';\n\nexport default [\n {\n 'en-US': {\n [translationKey]: {\n 'plugin name': 'Threads',\n 'thread title placeholder': 'New thread',\n 'thread title label': 'Title',\n 'delete thread label': 'Delete',\n 'create thread label': 'Create thread',\n 'message placeholder': 'Enter message...',\n 'comment placeholder': 'Enter comment...',\n 'settings standalone label': 'Enable standalone thread creation',\n 'anonymous label': 'Anonymous',\n 'enter to send message': 'Enter to add ⏎',\n },\n },\n },\n];\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { ArrowBendLeftDown, Spinner } from '@phosphor-icons/react';\nimport React, { type ComponentProps, type ComponentPropsWithRef, forwardRef } from 'react';\n\nimport { type ThemedClassName, useTranslation } from '@dxos/react-ui';\nimport { hoverableControlItem, hoverableFocusedWithinControls, mx } from '@dxos/react-ui-theme';\n\nimport { translationKey } from '../translations';\nimport type { ThreadEntity } from '../types';\n\nexport type ThreadProps = ThemedClassName<ComponentPropsWithRef<'div'>> &\n ThreadEntity & { current?: boolean | ComponentProps<'div'>['aria-current'] };\n\nexport const threadLayout = 'is-full place-self-start grid grid-cols-[var(--rail-size)_1fr]';\n\nexport const Thread = forwardRef<HTMLDivElement, ThreadProps>(\n ({ current, children, classNames, ...props }, forwardedRef) => {\n return (\n <div\n role='group'\n data-testid='thread'\n {...(current && { 'aria-current': typeof current === 'string' ? current : 'location' })}\n {...props}\n className={mx(\n threadLayout,\n hoverableFocusedWithinControls,\n 'bg-[var(--surface-bg)] border-[color:var(--surface-separator)] border-bs border-be plb-1.5 attention attention-within attention-current [--controls-opacity:0]',\n classNames,\n )}\n ref={forwardedRef}\n >\n {children}\n </div>\n );\n },\n);\n\nexport type ThreadHeadingProps = ThemedClassName<ComponentPropsWithRef<'div'>> & { detached?: boolean };\n\nexport const ThreadHeading = forwardRef<HTMLParagraphElement, ThreadHeadingProps>(\n ({ classNames, children, detached, ...props }, forwardedRef) => {\n return (\n <>\n <div role='none' className='grid place-items-end pie-3.5 fg-description'>\n <ArrowBendLeftDown />\n </div>\n <p\n role='heading'\n data-testid='thread.heading'\n {...props}\n className={mx(\n 'fg-description font-medium truncate before:content-[open-quote] after:content-[close-quote]',\n detached && 'line-through decoration-1',\n )}\n ref={forwardedRef}\n >\n {children}\n </p>\n </>\n );\n },\n);\n\nexport type ThreadFooterProps = ThemedClassName<ComponentPropsWithRef<'div'>> & {\n activity?: boolean;\n};\n\nexport const ThreadFooter = forwardRef<HTMLDivElement, ThreadFooterProps>(\n ({ activity, classNames, children, ...props }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n return (\n <div\n {...props}\n className={mx('col-start-2 grid grid-cols-[min-content_1fr_max-content] text-xs fg-description', classNames)}\n ref={forwardedRef}\n >\n <Spinner\n weight='bold'\n data-visible={activity ? 'show' : 'hide'}\n className='is-6 bs-4 invisible data-[visible=show]:visible animate-spin-slow'\n />\n <span className='truncate min-is-0' aria-live='polite'>\n {activity ? children : null}\n </span>\n <span className={mx('text-end pie-1', hoverableControlItem)}>{t('enter to send message')}</span>\n </div>\n );\n },\n);\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { X } from '@phosphor-icons/react';\nimport { formatDistanceToNow } from 'date-fns/formatDistanceToNow';\nimport React, { type ComponentPropsWithRef, type FC, forwardRef, useMemo } from 'react';\n\nimport { Avatar, Button, type ThemedClassName, useTranslation } from '@dxos/react-ui';\nimport { TextEditor, type TextEditorProps, keymap, type EditorView, listener } from '@dxos/react-ui-editor';\nimport {\n focusRing,\n hoverableControlItem,\n hoverableControls,\n hoverableFocusedWithinControls,\n mx,\n} from '@dxos/react-ui-theme';\nimport { safeParseJson, hexToEmoji, hexToHue } from '@dxos/util';\n\nimport { translationKey } from '../translations';\nimport { type MessageEntity, type MessageEntityBlock, type MessageMetadata } from '../types';\n\nconst avatarSize = 7;\nconst messageCell = 'plb-1 min-is-0';\n\nexport type MessageMetaProps = ThemedClassName<ComponentPropsWithRef<'div'>> &\n MessageMetadata &\n Partial<{ continues: boolean }>;\n\nexport const MessageMeta = forwardRef<HTMLDivElement, MessageMetaProps>(\n (\n { authorImgSrc, authorId, authorName, authorAvatarProps, continues = true, children, classNames, ...rootProps },\n forwardedRef,\n ) => {\n return (\n <Avatar.Root size={avatarSize} hue={authorAvatarProps?.hue || hexToHue(authorId ?? '0')}>\n <div\n role='none'\n data-testid='thread.message'\n {...rootProps}\n className={mx('grid grid-cols-subgrid col-span-2', classNames)}\n ref={forwardedRef}\n >\n <div role='none' className={mx('flex flex-col items-center gap-2', messageCell)}>\n <Avatar.Frame>\n <Avatar.Fallback text={authorAvatarProps?.emoji || hexToEmoji(authorId ?? '0')} />\n {authorImgSrc && <Avatar.Image href={authorImgSrc} />}\n </Avatar.Frame>\n {continues && <div role='none' className='is-px grow surface-separator' />}\n </div>\n <div role='none' className={messageCell}>\n {children}\n </div>\n </div>\n </Avatar.Root>\n );\n },\n);\n\nexport type MessageBlockProps<BlockValue> = {\n block: MessageEntityBlock<BlockValue>;\n authorId?: string;\n onBlockDelete?: () => void;\n};\n\nconst DefaultMessageBlock = ({ block, onBlockDelete }: MessageBlockProps<{ data?: any; text?: string }>) => {\n const contentWidth = onBlockDelete ? 'col-span-2' : 'col-span-3';\n return (\n <div\n role='none'\n className={mx('grid grid-cols-subgrid col-span-3', hoverableControls, hoverableFocusedWithinControls)}\n >\n {block.data ? (\n <pre className={mx('font-mono max-is-full overflow-x-auto', contentWidth)}>\n <code>{JSON.stringify(safeParseJson(block.data), undefined, 2)}</code>\n </pre>\n ) : (\n <p className={contentWidth}>{block.text ?? ''}</p>\n )}\n {onBlockDelete && (\n <Button\n variant='ghost'\n classNames={['p-1.5 min-bs-0 mie-1 items-start transition-opacity', hoverableControlItem]}\n onClick={() => onBlockDelete()}\n >\n <X />\n </Button>\n )}\n </div>\n );\n};\n\nexport type MessageProps<BlockValue> = MessageEntity<BlockValue> & {\n onDelete?: (messageId: string, blockIndex: number) => void;\n MessageBlockComponent?: FC<MessageBlockProps<BlockValue>>;\n};\n\nexport const Message = <BlockValue,>(props: MessageProps<BlockValue>) => {\n const { id, authorName, onDelete, blocks, MessageBlockComponent = DefaultMessageBlock, ...metaProps } = props;\n const { t, dtLocale } = useTranslation(translationKey);\n const firstBlock = blocks[0];\n const dt = firstBlock.timestamp ? new Date(firstBlock.timestamp) : undefined;\n\n return (\n <MessageMeta {...metaProps} id={id} continues>\n <p className='grid grid-cols-[1fr_max-content] gap-2 pie-2'>\n <Avatar.Label classNames={['truncate text-sm font-medium', !authorName && 'fg-description']}>\n {authorName ?? t('anonymous label')}\n </Avatar.Label>\n <time className='fg-description text-xs pbs-0.5' dateTime={dt?.toISOString()}>\n {dt ? formatDistanceToNow(dt, { locale: dtLocale, addSuffix: true }) : ''}\n </time>\n </p>\n <div role='none' className='grid gap-y-1 grid-cols-[min-content_1fr_min-content]'>\n {blocks.map((block, i) => (\n <MessageBlockComponent\n key={i}\n block={block}\n authorId={metaProps.authorId}\n onBlockDelete={onDelete && (() => onDelete(id, i))}\n />\n ))}\n </div>\n </MessageMeta>\n );\n};\n\nexport type MessageTextboxProps = {\n onSend?: () => void;\n onClear?: () => void;\n onEditorFocus?: () => void;\n disabled?: boolean;\n} & Omit<MessageMetadata, 'id'> &\n TextEditorProps;\n\nexport const MessageTextbox = forwardRef<EditorView, MessageTextboxProps>(\n (\n {\n onSend,\n onClear,\n onEditorFocus,\n authorId,\n authorName,\n authorImgSrc,\n authorAvatarProps,\n disabled,\n extensions: _extensions,\n ...editorProps\n },\n forwardedRef,\n ) => {\n const extensions = useMemo(\n () => [\n ...(_extensions ?? []),\n keymap.of([\n {\n key: 'Enter',\n run: () => {\n if (onSend) {\n onSend();\n return true;\n } else {\n return false;\n }\n },\n },\n {\n key: 'Meta+Backspace',\n run: () => {\n if (onClear) {\n onClear();\n return true;\n } else {\n return false;\n }\n },\n },\n ]),\n listener({\n onFocus: (focused) => {\n if (focused) {\n onEditorFocus?.();\n }\n },\n }),\n ],\n [_extensions, onSend, onClear, onEditorFocus],\n );\n\n return (\n <MessageMeta\n {...{ id: editorProps.model.id, authorId, authorName, authorImgSrc, authorAvatarProps }}\n continues={false}\n >\n {/* TODO(burdon): Change to hook. */}\n <TextEditor\n slots={{ root: { className: mx('plb-0.5 mie-1 rounded-sm', focusRing, disabled && 'opacity-50') } }}\n readonly={disabled}\n extensions={extensions}\n {...editorProps}\n ref={forwardedRef}\n />\n </MessageMeta>\n );\n },\n);\n"],
5
+ "mappings": ";AAIO,IAAMA,iBAAiB;AAE9B,IAAA,uBAAe;EACb;IACE,SAAS;MACP,CAACA,cAAAA,GAAiB;QAChB,eAAe;QACf,4BAA4B;QAC5B,sBAAsB;QACtB,uBAAuB;QACvB,uBAAuB;QACvB,uBAAuB;QACvB,uBAAuB;QACvB,6BAA6B;QAC7B,mBAAmB;QACnB,yBAAyB;MAC3B;IACF;EACF;;;;AClBF,SAASC,mBAAmBC,eAAe;AAC3C,OAAOC,SAA0DC,kBAAkB;AAEnF,SAA+BC,sBAAsB;AACrD,SAASC,sBAAsBC,gCAAgCC,UAAU;AAQlE,IAAMC,eAAe;AAErB,IAAMC,SAASC,2BACpB,CAAC,EAAEC,SAASC,UAAUC,YAAY,GAAGC,MAAAA,GAASC,iBAAAA;AAC5C,SACE,sBAAA,cAACC,OAAAA;IACCC,MAAK;IACLC,eAAY;IACX,GAAIP,WAAW;MAAE,gBAAgB,OAAOA,YAAY,WAAWA,UAAU;IAAW;IACpF,GAAGG;IACJK,WAAWC,GACTZ,cACAa,gCACA,kKACAR,UAAAA;IAEFS,KAAKP;KAEJH,QAAAA;AAGP,CAAA;AAKK,IAAMW,gBAAgBb,2BAC3B,CAAC,EAAEG,YAAYD,UAAUY,UAAU,GAAGV,MAAAA,GAASC,iBAAAA;AAC7C,SACE,sBAAA,cAAA,MAAA,UAAA,MACE,sBAAA,cAACC,OAAAA;IAAIC,MAAK;IAAOE,WAAU;KACzB,sBAAA,cAACM,mBAAAA,IAAAA,CAAAA,GAEH,sBAAA,cAACC,KAAAA;IACCT,MAAK;IACLC,eAAY;IACX,GAAGJ;IACJK,WAAWC,GACT,+FACAI,YAAY,2BAAA;IAEdF,KAAKP;KAEJH,QAAAA,CAAAA;AAIT,CAAA;AAOK,IAAMe,eAAejB,2BAC1B,CAAC,EAAEkB,UAAUf,YAAYD,UAAU,GAAGE,MAAAA,GAASC,iBAAAA;AAC7C,QAAM,EAAEc,EAAC,IAAKC,eAAeC,cAAAA;AAC7B,SACE,sBAAA,cAACf,OAAAA;IACE,GAAGF;IACJK,WAAWC,GAAG,mFAAmFP,UAAAA;IACjGS,KAAKP;KAEL,sBAAA,cAACiB,SAAAA;IACCC,QAAO;IACPC,gBAAcN,WAAW,SAAS;IAClCT,WAAU;MAEZ,sBAAA,cAACgB,QAAAA;IAAKhB,WAAU;IAAoBiB,aAAU;KAC3CR,WAAWhB,WAAW,IAAA,GAEzB,sBAAA,cAACuB,QAAAA;IAAKhB,WAAWC,GAAG,kBAAkBiB,oBAAAA;KAAwBR,EAAE,uBAAA,CAAA,CAAA;AAGtE,CAAA;;;ACtFF,SAASS,SAAS;AAClB,SAASC,2BAA2B;AACpC,OAAOC,UAA8CC,cAAAA,aAAYC,eAAe;AAEhF,SAASC,QAAQC,QAA8BC,kBAAAA,uBAAsB;AACrE,SAASC,YAAkCC,QAAyBC,gBAAgB;AACpF,SACEC,WACAC,wBAAAA,uBACAC,mBACAC,kCAAAA,iCACAC,MAAAA,WACK;AACP,SAASC,eAAeC,YAAYC,gBAAgB;AAKpD,IAAMC,aAAa;AACnB,IAAMC,cAAc;AAMb,IAAMC,cAAcC,gBAAAA,YACzB,CACE,EAAEC,cAAcC,UAAUC,YAAYC,mBAAmBC,YAAY,MAAMC,UAAUC,YAAY,GAAGC,UAAAA,GACpGC,iBAAAA;AAEA,SACE,gBAAAC,OAAA,cAACC,OAAOC,MAAI;IAACC,MAAMhB;IAAYiB,KAAKV,mBAAmBU,OAAOC,SAASb,YAAY,GAAA;KACjF,gBAAAQ,OAAA,cAACM,OAAAA;IACCC,MAAK;IACLC,eAAY;IACX,GAAGV;IACJW,WAAWC,IAAG,qCAAqCb,UAAAA;IACnDc,KAAKZ;KAEL,gBAAAC,OAAA,cAACM,OAAAA;IAAIC,MAAK;IAAOE,WAAWC,IAAG,oCAAoCtB,WAAAA;KACjE,gBAAAY,OAAA,cAACC,OAAOW,OAAK,MACX,gBAAAZ,OAAA,cAACC,OAAOY,UAAQ;IAACC,MAAMpB,mBAAmBqB,SAASC,WAAWxB,YAAY,GAAA;MACzED,gBAAgB,gBAAAS,OAAA,cAACC,OAAOgB,OAAK;IAACC,MAAM3B;OAEtCI,aAAa,gBAAAK,OAAA,cAACM,OAAAA;IAAIC,MAAK;IAAOE,WAAU;OAE3C,gBAAAT,OAAA,cAACM,OAAAA;IAAIC,MAAK;IAAOE,WAAWrB;KACzBQ,QAAAA,CAAAA,CAAAA;AAKX,CAAA;AASF,IAAMuB,sBAAsB,CAAC,EAAEC,OAAOC,cAAa,MAAoD;AACrG,QAAMC,eAAeD,gBAAgB,eAAe;AACpD,SACE,gBAAArB,OAAA,cAACM,OAAAA;IACCC,MAAK;IACLE,WAAWC,IAAG,qCAAqCa,mBAAmBC,+BAAAA;KAErEJ,MAAMK,OACL,gBAAAzB,OAAA,cAAC0B,OAAAA;IAAIjB,WAAWC,IAAG,yCAAyCY,YAAAA;KAC1D,gBAAAtB,OAAA,cAAC2B,QAAAA,MAAMC,KAAKC,UAAUC,cAAcV,MAAMK,IAAI,GAAGM,QAAW,CAAA,CAAA,CAAA,IAG9D,gBAAA/B,OAAA,cAACgC,KAAAA;IAAEvB,WAAWa;KAAeF,MAAMN,QAAQ,EAAA,GAE5CO,iBACC,gBAAArB,OAAA,cAACiC,QAAAA;IACCC,SAAQ;IACRrC,YAAY;MAAC;MAAuDsC;;IACpEC,SAAS,MAAMf,cAAAA;KAEf,gBAAArB,OAAA,cAACqC,GAAAA,IAAAA,CAAAA,CAAAA;AAKX;AAOO,IAAMC,UAAU,CAAcC,UAAAA;AACnC,QAAM,EAAEC,IAAI/C,YAAYgD,UAAUC,QAAQC,wBAAwBxB,qBAAqB,GAAGyB,UAAAA,IAAcL;AACxG,QAAM,EAAEM,GAAGC,SAAQ,IAAKC,gBAAeC,cAAAA;AACvC,QAAMC,aAAaP,OAAO,CAAA;AAC1B,QAAMQ,KAAKD,WAAWE,YAAY,IAAIC,KAAKH,WAAWE,SAAS,IAAIpB;AAEnE,SACE,gBAAA/B,OAAA,cAACX,aAAAA;IAAa,GAAGuD;IAAWJ;IAAQ7C,WAAAA;KAClC,gBAAAK,OAAA,cAACgC,KAAAA;IAAEvB,WAAU;KACX,gBAAAT,OAAA,cAACC,OAAOoD,OAAK;IAACxD,YAAY;MAAC;MAAgC,CAACJ,cAAc;;KACvEA,cAAcoD,EAAE,iBAAA,CAAA,GAEnB,gBAAA7C,OAAA,cAACsD,QAAAA;IAAK7C,WAAU;IAAiC8C,UAAUL,IAAIM,YAAAA;KAC5DN,KAAKO,oBAAoBP,IAAI;IAAEQ,QAAQZ;IAAUa,WAAW;EAAK,CAAA,IAAK,EAAA,CAAA,GAG3E,gBAAA3D,OAAA,cAACM,OAAAA;IAAIC,MAAK;IAAOE,WAAU;KACxBiC,OAAOkB,IAAI,CAACxC,OAAOyC,MAClB,gBAAA7D,OAAA,cAAC2C,uBAAAA;IACCmB,KAAKD;IACLzC;IACA5B,UAAUoD,UAAUpD;IACpB6B,eAAeoB,aAAa,MAAMA,SAASD,IAAIqB,CAAAA;;AAM3D;AAUO,IAAME,iBAAiBzE,gBAAAA,YAC5B,CACE,EACE0E,QACAC,SACAC,eACA1E,UACAC,YACAF,cACAG,mBACAyE,UACAC,YAAYC,aACZ,GAAGC,YAAAA,GAELvE,iBAAAA;AAEA,QAAMqE,aAAaG,QACjB,MAAM;OACAF,eAAe,CAAA;IACnBG,OAAOC,GAAG;MACR;QACEX,KAAK;QACLY,KAAK,MAAA;AACH,cAAIV,QAAQ;AACVA,mBAAAA;AACA,mBAAO;UACT,OAAO;AACL,mBAAO;UACT;QACF;MACF;MACA;QACEF,KAAK;QACLY,KAAK,MAAA;AACH,cAAIT,SAAS;AACXA,oBAAAA;AACA,mBAAO;UACT,OAAO;AACL,mBAAO;UACT;QACF;MACF;KACD;IACDU,SAAS;MACPC,SAAS,CAACC,YAAAA;AACR,YAAIA,SAAS;AACXX,0BAAAA;QACF;MACF;IACF,CAAA;KAEF;IAACG;IAAaL;IAAQC;IAASC;GAAc;AAG/C,SACE,gBAAAlE,OAAA,cAACX,aAAAA;IACOmD,IAAI8B,YAAYQ,MAAMtC;IAAIhD;IAAUC;IAAYF;IAAcG;IACpEC,WAAW;KAGX,gBAAAK,OAAA,cAAC+E,YAAAA;IACCC,OAAO;MAAEC,MAAM;QAAExE,WAAWC,IAAG,4BAA4BwE,WAAWf,YAAY,YAAA;MAAc;IAAE;IAClGgB,UAAUhB;IACVC;IACC,GAAGE;IACJ3D,KAAKZ;;AAIb,CAAA;",
6
+ "names": ["translationKey", "ArrowBendLeftDown", "Spinner", "React", "forwardRef", "useTranslation", "hoverableControlItem", "hoverableFocusedWithinControls", "mx", "threadLayout", "Thread", "forwardRef", "current", "children", "classNames", "props", "forwardedRef", "div", "role", "data-testid", "className", "mx", "hoverableFocusedWithinControls", "ref", "ThreadHeading", "detached", "ArrowBendLeftDown", "p", "ThreadFooter", "activity", "t", "useTranslation", "translationKey", "Spinner", "weight", "data-visible", "span", "aria-live", "hoverableControlItem", "X", "formatDistanceToNow", "React", "forwardRef", "useMemo", "Avatar", "Button", "useTranslation", "TextEditor", "keymap", "listener", "focusRing", "hoverableControlItem", "hoverableControls", "hoverableFocusedWithinControls", "mx", "safeParseJson", "hexToEmoji", "hexToHue", "avatarSize", "messageCell", "MessageMeta", "forwardRef", "authorImgSrc", "authorId", "authorName", "authorAvatarProps", "continues", "children", "classNames", "rootProps", "forwardedRef", "React", "Avatar", "Root", "size", "hue", "hexToHue", "div", "role", "data-testid", "className", "mx", "ref", "Frame", "Fallback", "text", "emoji", "hexToEmoji", "Image", "href", "DefaultMessageBlock", "block", "onBlockDelete", "contentWidth", "hoverableControls", "hoverableFocusedWithinControls", "data", "pre", "code", "JSON", "stringify", "safeParseJson", "undefined", "p", "Button", "variant", "hoverableControlItem", "onClick", "X", "Message", "props", "id", "onDelete", "blocks", "MessageBlockComponent", "metaProps", "t", "dtLocale", "useTranslation", "translationKey", "firstBlock", "dt", "timestamp", "Date", "Label", "time", "dateTime", "toISOString", "formatDistanceToNow", "locale", "addSuffix", "map", "i", "key", "MessageTextbox", "onSend", "onClear", "onEditorFocus", "disabled", "extensions", "_extensions", "editorProps", "useMemo", "keymap", "of", "run", "listener", "onFocus", "focused", "model", "TextEditor", "slots", "root", "focusRing", "readonly"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/ui/react-ui-thread/src/translations.ts":{"bytes":2281,"imports":[],"format":"esm"},"packages/ui/react-ui-thread/src/Thread/Thread.tsx":{"bytes":9343,"imports":[{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-thread/src/translations.ts","kind":"import-statement","original":"../translations"}],"format":"esm"},"packages/ui/react-ui-thread/src/Thread/index.ts":{"bytes":472,"imports":[{"path":"packages/ui/react-ui-thread/src/Thread/Thread.tsx","kind":"import-statement","original":"./Thread"}],"format":"esm"},"packages/ui/react-ui-thread/src/Message/Message.tsx":{"bytes":19971,"imports":[{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"date-fns/formatDistanceToNow","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-editor","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-thread/src/translations.ts","kind":"import-statement","original":"../translations"}],"format":"esm"},"packages/ui/react-ui-thread/src/Message/index.ts":{"bytes":474,"imports":[{"path":"packages/ui/react-ui-thread/src/Message/Message.tsx","kind":"import-statement","original":"./Message"}],"format":"esm"},"packages/ui/react-ui-thread/src/types.ts":{"bytes":1115,"imports":[],"format":"esm"},"packages/ui/react-ui-thread/src/index.ts":{"bytes":877,"imports":[{"path":"packages/ui/react-ui-thread/src/translations.ts","kind":"import-statement","original":"./translations"},{"path":"packages/ui/react-ui-thread/src/Thread/index.ts","kind":"import-statement","original":"./Thread"},{"path":"packages/ui/react-ui-thread/src/Message/index.ts","kind":"import-statement","original":"./Message"},{"path":"packages/ui/react-ui-thread/src/types.ts","kind":"import-statement","original":"./types"}],"format":"esm"}},"outputs":{"packages/ui/react-ui-thread/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":16824},"packages/ui/react-ui-thread/dist/lib/browser/index.mjs":{"imports":[{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"date-fns/formatDistanceToNow","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-editor","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["Message","MessageMeta","MessageTextbox","Thread","ThreadFooter","ThreadHeading","threadLayout","translations"],"entryPoint":"packages/ui/react-ui-thread/src/index.ts","inputs":{"packages/ui/react-ui-thread/src/translations.ts":{"bytesInOutput":609},"packages/ui/react-ui-thread/src/Thread/Thread.tsx":{"bytesInOutput":2487},"packages/ui/react-ui-thread/src/Thread/index.ts":{"bytesInOutput":0},"packages/ui/react-ui-thread/src/index.ts":{"bytesInOutput":0},"packages/ui/react-ui-thread/src/Message/Message.tsx":{"bytesInOutput":5333},"packages/ui/react-ui-thread/src/Message/index.ts":{"bytesInOutput":0}},"bytes":8779}}}
1
+ {"inputs":{"packages/ui/react-ui-thread/src/translations.ts":{"bytes":2281,"imports":[],"format":"esm"},"packages/ui/react-ui-thread/src/Thread/Thread.tsx":{"bytes":9343,"imports":[{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-thread/src/translations.ts","kind":"import-statement","original":"../translations"}],"format":"esm"},"packages/ui/react-ui-thread/src/Thread/index.ts":{"bytes":472,"imports":[{"path":"packages/ui/react-ui-thread/src/Thread/Thread.tsx","kind":"import-statement","original":"./Thread"}],"format":"esm"},"packages/ui/react-ui-thread/src/Message/Message.tsx":{"bytes":20678,"imports":[{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"date-fns/formatDistanceToNow","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-editor","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/ui/react-ui-thread/src/translations.ts","kind":"import-statement","original":"../translations"}],"format":"esm"},"packages/ui/react-ui-thread/src/Message/index.ts":{"bytes":474,"imports":[{"path":"packages/ui/react-ui-thread/src/Message/Message.tsx","kind":"import-statement","original":"./Message"}],"format":"esm"},"packages/ui/react-ui-thread/src/types.ts":{"bytes":1115,"imports":[],"format":"esm"},"packages/ui/react-ui-thread/src/index.ts":{"bytes":877,"imports":[{"path":"packages/ui/react-ui-thread/src/translations.ts","kind":"import-statement","original":"./translations"},{"path":"packages/ui/react-ui-thread/src/Thread/index.ts","kind":"import-statement","original":"./Thread"},{"path":"packages/ui/react-ui-thread/src/Message/index.ts","kind":"import-statement","original":"./Message"},{"path":"packages/ui/react-ui-thread/src/types.ts","kind":"import-statement","original":"./types"}],"format":"esm"}},"outputs":{"packages/ui/react-ui-thread/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":17219},"packages/ui/react-ui-thread/dist/lib/browser/index.mjs":{"imports":[{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"date-fns/formatDistanceToNow","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-editor","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["Message","MessageMeta","MessageTextbox","Thread","ThreadFooter","ThreadHeading","threadLayout","translations"],"entryPoint":"packages/ui/react-ui-thread/src/index.ts","inputs":{"packages/ui/react-ui-thread/src/translations.ts":{"bytesInOutput":609},"packages/ui/react-ui-thread/src/Thread/Thread.tsx":{"bytesInOutput":2487},"packages/ui/react-ui-thread/src/Thread/index.ts":{"bytesInOutput":0},"packages/ui/react-ui-thread/src/index.ts":{"bytesInOutput":0},"packages/ui/react-ui-thread/src/Message/Message.tsx":{"bytesInOutput":5458},"packages/ui/react-ui-thread/src/Message/index.ts":{"bytesInOutput":0}},"bytes":8904}}}
@@ -1,6 +1,6 @@
1
1
  import React, { type ComponentPropsWithRef, type FC } from 'react';
2
2
  import { type ThemedClassName } from '@dxos/react-ui';
3
- import { type TextEditorProps } from '@dxos/react-ui-editor';
3
+ import { type TextEditorProps, type EditorView } from '@dxos/react-ui-editor';
4
4
  import { type MessageEntity, type MessageEntityBlock, type MessageMetadata } from '../types';
5
5
  export type MessageMetaProps = ThemedClassName<ComponentPropsWithRef<'div'>> & MessageMetadata & Partial<{
6
6
  continues: boolean;
@@ -17,10 +17,15 @@ export type MessageProps<BlockValue> = MessageEntity<BlockValue> & {
17
17
  };
18
18
  export declare const Message: <BlockValue>(props: MessageProps<BlockValue>) => JSX.Element;
19
19
  export type MessageTextboxProps = {
20
- disabled?: boolean;
21
20
  onSend?: () => void;
22
21
  onClear?: () => void;
23
22
  onEditorFocus?: () => void;
24
- } & MessageMetadata & TextEditorProps;
25
- export declare const MessageTextbox: ({ id, onSend, onClear, onEditorFocus, authorId, authorName, authorImgSrc, authorAvatarProps, disabled, extensions: _extensions, ...editorProps }: MessageTextboxProps) => JSX.Element;
23
+ disabled?: boolean;
24
+ } & Omit<MessageMetadata, 'id'> & TextEditorProps;
25
+ export declare const MessageTextbox: React.ForwardRefExoticComponent<{
26
+ onSend?: (() => void) | undefined;
27
+ onClear?: (() => void) | undefined;
28
+ onEditorFocus?: (() => void) | undefined;
29
+ disabled?: boolean | undefined;
30
+ } & Omit<MessageMetadata, "id"> & TextEditorProps & React.RefAttributes<EditorView>>;
26
31
  //# sourceMappingURL=Message.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../../../src/Message/Message.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,KAAK,qBAAqB,EAAE,KAAK,EAAE,EAAuB,MAAM,OAAO,CAAC;AAGxF,OAAO,EAAkB,KAAK,eAAe,EAAkB,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,KAAK,eAAe,EAAgC,MAAM,uBAAuB,CAAC;AAW3F,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAI7F,MAAM,MAAM,gBAAgB,GAAG,eAAe,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,GAC1E,eAAe,GACf,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAElC,eAAO,MAAM,WAAW,qnJA4BvB,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,UAAU,IAAI;IAC1C,KAAK,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC;AA6BF,MAAM,MAAM,YAAY,CAAC,UAAU,IAAI,aAAa,CAAC,UAAU,CAAC,GAAG;IACjE,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,qBAAqB,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;CAC3D,CAAC;AAEF,eAAO,MAAM,OAAO,8DA4BnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B,GAAG,eAAe,GACjB,eAAe,CAAC;AA4BlB,eAAO,MAAM,cAAc,qJAYxB,mBAAmB,gBAwBrB,CAAC"}
1
+ {"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../../../src/Message/Message.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,KAAK,qBAAqB,EAAE,KAAK,EAAE,EAAuB,MAAM,OAAO,CAAC;AAExF,OAAO,EAAkB,KAAK,eAAe,EAAkB,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAc,KAAK,eAAe,EAAU,KAAK,UAAU,EAAY,MAAM,uBAAuB,CAAC;AAW5G,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAK7F,MAAM,MAAM,gBAAgB,GAAG,eAAe,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,GAC1E,eAAe,GACf,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAElC,eAAO,MAAM,WAAW,qnJA4BvB,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,UAAU,IAAI;IAC1C,KAAK,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC;AA6BF,MAAM,MAAM,YAAY,CAAC,UAAU,IAAI,aAAa,CAAC,UAAU,CAAC,GAAG;IACjE,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,qBAAqB,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;CAC3D,CAAC;AAEF,eAAO,MAAM,OAAO,8DA4BnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,GAC7B,eAAe,CAAC;AAElB,eAAO,MAAM,cAAc;oBAPV,IAAI;qBACH,IAAI;2BACE,IAAI;;oFA2E3B,CAAC"}
@@ -52,4 +52,10 @@ export declare const Default: {
52
52
  text: string;
53
53
  };
54
54
  };
55
+ export declare const Testing: {
56
+ args: {
57
+ text: string;
58
+ autoCreate: boolean;
59
+ };
60
+ };
55
61
  //# sourceMappingURL=Comments.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Comments.stories.d.ts","sourceRoot":"","sources":["../../../../src/Thread/Comments.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;AAGpB,OAAO,KAAwD,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAkB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAK/D,OAAO,EAML,KAAK,KAAK,EAMX,MAAM,uBAAuB,CAAC;AAM/B,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAoE9C,KAAK,kBAAkB,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,EAAE,CAAC;CACjD,CAAC;AAqIF,KAAK,UAAU,GAAG;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;;;;;;;;;;mBA+He,UAAU;;;;;;;;;;;;;;;;;;;;;AAJ3B,wBAME;AAWF,eAAO,MAAM,OAAO;;;;CAInB,CAAC"}
1
+ {"version":3,"file":"Comments.stories.d.ts","sourceRoot":"","sources":["../../../../src/Thread/Comments.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;AAGpB,OAAO,KAAwD,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAK/C,OAAO,EAOL,KAAK,KAAK,EAIX,MAAM,uBAAuB,CAAC;AAM/B,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAkE9C,KAAK,kBAAkB,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,EAAE,CAAC;CACjD,CAAC;AAiHF,KAAK,UAAU,GAAG;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;;;;;;;;;;mBA8He,UAAU;;;;;;;;;;;;;;;;;;;;;AAJ3B,wBAME;AAWF,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAEF,eAAO,MAAM,OAAO;;;;;CAKnB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Thread.stories.d.ts","sourceRoot":"","sources":["../../../../src/Thread/Thread.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;AACpB,OAAO,KAA4B,MAAM,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;AAwEjD,wBAME;AAEF,eAAO,MAAM,OAAO,IAAK,CAAC"}
1
+ {"version":3,"file":"Thread.stories.d.ts","sourceRoot":"","sources":["../../../../src/Thread/Thread.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;AAEpB,OAAO,KAAmB,MAAM,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;AA+DxC,wBAME;AAEF,eAAO,MAAM,OAAO,IAAK,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-thread",
3
- "version": "0.4.8-main.0602afb",
3
+ "version": "0.4.8-main.2d8e727",
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",
@@ -18,11 +18,11 @@
18
18
  "dependencies": {
19
19
  "@radix-ui/react-primitive": "^1.0.2",
20
20
  "date-fns": "^3.3.1",
21
- "@dxos/react-ui": "0.4.8-main.0602afb",
22
- "@dxos/react-ui-editor": "0.4.8-main.0602afb",
23
- "@dxos/react-ui-theme": "0.4.8-main.0602afb",
24
- "@dxos/react-ui-mosaic": "0.4.8-main.0602afb",
25
- "@dxos/util": "0.4.8-main.0602afb"
21
+ "@dxos/react-ui": "0.4.8-main.2d8e727",
22
+ "@dxos/react-ui-editor": "0.4.8-main.2d8e727",
23
+ "@dxos/react-ui-theme": "0.4.8-main.2d8e727",
24
+ "@dxos/util": "0.4.8-main.2d8e727",
25
+ "@dxos/react-ui-mosaic": "0.4.8-main.2d8e727"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@phosphor-icons/react": "^2.0.5",
@@ -32,11 +32,11 @@
32
32
  "react-dom": "^18.2.0",
33
33
  "vite": "^5.1.5",
34
34
  "vite-plugin-turbosnap": "^1.0.2",
35
- "@dxos/echo-schema": "0.4.8-main.0602afb",
36
- "@dxos/log": "0.4.8-main.0602afb",
37
- "@dxos/random": "0.4.8-main.0602afb",
38
- "@dxos/storybook-utils": "0.4.8-main.0602afb",
39
- "@dxos/keys": "0.4.8-main.0602afb"
35
+ "@dxos/keys": "0.4.8-main.2d8e727",
36
+ "@dxos/echo-schema": "0.4.8-main.2d8e727",
37
+ "@dxos/log": "0.4.8-main.2d8e727",
38
+ "@dxos/random": "0.4.8-main.2d8e727",
39
+ "@dxos/storybook-utils": "0.4.8-main.2d8e727"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@phosphor-icons/react": "^2.0.5",
@@ -6,9 +6,8 @@ import { X } from '@phosphor-icons/react';
6
6
  import { formatDistanceToNow } from 'date-fns/formatDistanceToNow';
7
7
  import React, { type ComponentPropsWithRef, type FC, forwardRef, useMemo } from 'react';
8
8
 
9
- // TODO(burdon): Remove dep.
10
9
  import { Avatar, Button, type ThemedClassName, useTranslation } from '@dxos/react-ui';
11
- import { type TextEditorProps, keymap, listener, TextEditor } from '@dxos/react-ui-editor';
10
+ import { TextEditor, type TextEditorProps, keymap, type EditorView, listener } from '@dxos/react-ui-editor';
12
11
  import {
13
12
  focusRing,
14
13
  hoverableControlItem,
@@ -16,12 +15,13 @@ import {
16
15
  hoverableFocusedWithinControls,
17
16
  mx,
18
17
  } from '@dxos/react-ui-theme';
19
- import { safeParseJson, hexToEmoji, hexToHue, isNotFalsy } from '@dxos/util';
18
+ import { safeParseJson, hexToEmoji, hexToHue } from '@dxos/util';
20
19
 
21
20
  import { translationKey } from '../translations';
22
21
  import { type MessageEntity, type MessageEntityBlock, type MessageMetadata } from '../types';
23
22
 
24
23
  const avatarSize = 7;
24
+ const messageCell = 'plb-1 min-is-0';
25
25
 
26
26
  export type MessageMetaProps = ThemedClassName<ComponentPropsWithRef<'div'>> &
27
27
  MessageMetadata &
@@ -41,14 +41,14 @@ export const MessageMeta = forwardRef<HTMLDivElement, MessageMetaProps>(
41
41
  className={mx('grid grid-cols-subgrid col-span-2', classNames)}
42
42
  ref={forwardedRef}
43
43
  >
44
- <div role='none' className={mx('flex flex-col items-center gap-2 plb-2')}>
44
+ <div role='none' className={mx('flex flex-col items-center gap-2', messageCell)}>
45
45
  <Avatar.Frame>
46
46
  <Avatar.Fallback text={authorAvatarProps?.emoji || hexToEmoji(authorId ?? '0')} />
47
47
  {authorImgSrc && <Avatar.Image href={authorImgSrc} />}
48
48
  </Avatar.Frame>
49
49
  {continues && <div role='none' className='is-px grow surface-separator' />}
50
50
  </div>
51
- <div role='none' className='plb-1 min-is-0'>
51
+ <div role='none' className={messageCell}>
52
52
  {children}
53
53
  </div>
54
54
  </div>
@@ -126,73 +126,81 @@ export const Message = <BlockValue,>(props: MessageProps<BlockValue>) => {
126
126
  };
127
127
 
128
128
  export type MessageTextboxProps = {
129
- disabled?: boolean;
130
129
  onSend?: () => void;
131
130
  onClear?: () => void;
132
131
  onEditorFocus?: () => void;
133
- } & MessageMetadata &
132
+ disabled?: boolean;
133
+ } & Omit<MessageMetadata, 'id'> &
134
134
  TextEditorProps;
135
135
 
136
- const keyBindings = ({ onSend, onClear }: Pick<MessageTextboxProps, 'onSend' | 'onClear'>) => [
137
- {
138
- key: 'Enter',
139
- run: () => {
140
- if (onSend) {
141
- onSend();
142
- return true;
143
- } else {
144
- return false;
145
- }
146
- },
147
- },
148
- {
149
- // TODO(burdon): Other key bindings.
150
- key: 'Meta+Backspace',
151
- run: () => {
152
- if (onClear) {
153
- onClear();
154
- return true;
155
- } else {
156
- return false;
157
- }
136
+ export const MessageTextbox = forwardRef<EditorView, MessageTextboxProps>(
137
+ (
138
+ {
139
+ onSend,
140
+ onClear,
141
+ onEditorFocus,
142
+ authorId,
143
+ authorName,
144
+ authorImgSrc,
145
+ authorAvatarProps,
146
+ disabled,
147
+ extensions: _extensions,
148
+ ...editorProps
158
149
  },
159
- },
160
- ];
161
-
162
- export const MessageTextbox = ({
163
- id,
164
- onSend,
165
- onClear,
166
- onEditorFocus,
167
- authorId,
168
- authorName,
169
- authorImgSrc,
170
- authorAvatarProps,
171
- disabled,
172
- extensions: _extensions,
173
- ...editorProps
174
- }: MessageTextboxProps) => {
175
- const extensions = useMemo<TextEditorProps['extensions']>(() => {
176
- return [
177
- _extensions,
178
- keymap.of(keyBindings({ onSend, onClear })),
179
- listener({
180
- onFocus: (focusing) => {
181
- if (focusing) {
182
- onEditorFocus?.();
183
- }
184
- },
185
- }),
186
- ].filter(isNotFalsy);
187
- }, [_extensions]);
150
+ forwardedRef,
151
+ ) => {
152
+ const extensions = useMemo(
153
+ () => [
154
+ ...(_extensions ?? []),
155
+ keymap.of([
156
+ {
157
+ key: 'Enter',
158
+ run: () => {
159
+ if (onSend) {
160
+ onSend();
161
+ return true;
162
+ } else {
163
+ return false;
164
+ }
165
+ },
166
+ },
167
+ {
168
+ key: 'Meta+Backspace',
169
+ run: () => {
170
+ if (onClear) {
171
+ onClear();
172
+ return true;
173
+ } else {
174
+ return false;
175
+ }
176
+ },
177
+ },
178
+ ]),
179
+ listener({
180
+ onFocus: (focused) => {
181
+ if (focused) {
182
+ onEditorFocus?.();
183
+ }
184
+ },
185
+ }),
186
+ ],
187
+ [_extensions, onSend, onClear, onEditorFocus],
188
+ );
188
189
 
189
- return (
190
- <MessageMeta {...{ id, authorId, authorName, authorImgSrc, authorAvatarProps }} continues={false}>
191
- <TextEditor
192
- {...editorProps}
193
- extensions={extensions}
194
- className={mx('plb-0.5 mie-1 rounded-sm', focusRing, disabled && 'opacity-50')}
195
- />
196
- </MessageMeta>
197
- );
198
- };
190
+ return (
191
+ <MessageMeta
192
+ {...{ id: editorProps.model.id, authorId, authorName, authorImgSrc, authorAvatarProps }}
193
+ continues={false}
194
+ >
195
+ {/* TODO(burdon): Change to hook. */}
196
+ <TextEditor
197
+ slots={{ root: { className: mx('plb-0.5 mie-1 rounded-sm', focusRing, disabled && 'opacity-50') } }}
198
+ readonly={disabled}
199
+ extensions={extensions}
200
+ {...editorProps}
201
+ ref={forwardedRef}
202
+ />
203
+ </MessageMeta>
204
+ );
205
+ },
206
+ );
@@ -7,23 +7,22 @@ import '@dxosTheme';
7
7
  import { Check, Trash } from '@phosphor-icons/react';
8
8
  import React, { type FC, useEffect, useMemo, useRef, useState } from 'react';
9
9
 
10
- import { getTextContent, TextObject } from '@dxos/echo-schema';
10
+ import { TextObject } from '@dxos/echo-schema';
11
11
  import { PublicKey } from '@dxos/keys';
12
12
  import { log } from '@dxos/log';
13
13
  import { faker } from '@dxos/random';
14
- import { Button, useThemeContext } from '@dxos/react-ui';
14
+ import { Button } from '@dxos/react-ui';
15
15
  import {
16
+ MarkdownEditor,
16
17
  comments,
17
18
  type CommentsOptions,
18
19
  focusComment,
19
20
  useComments,
20
21
  type Comment,
21
22
  type Range,
22
- useTextEditor,
23
- createBasicExtensions,
24
- createThemeExtensions,
25
- automerge,
26
- useDocAccessor,
23
+ useTextModel,
24
+ type EditorView,
25
+ TextEditor,
27
26
  } from '@dxos/react-ui-editor';
28
27
  import { withTheme } from '@dxos/storybook-utils';
29
28
 
@@ -59,39 +58,37 @@ const Editor: FC<{
59
58
  onUpdateComment,
60
59
  onSelectComment,
61
60
  }) => {
61
+ const model = useTextModel({ text: item.text });
62
+ const view = useRef<EditorView>(null);
62
63
  const [selected, setSelected] = useState<string>();
63
-
64
- const { themeMode } = useThemeContext();
65
- const { doc, accessor } = useDocAccessor(item.text);
66
- const { parentRef, view } = useTextEditor(
67
- () => ({
68
- id,
69
- doc,
70
- extensions: [
71
- createBasicExtensions(),
72
- createThemeExtensions({ themeMode }),
73
- automerge(accessor),
74
- comments({
75
- onCreate: onCreateComment,
76
- onDelete: onDeleteComment,
77
- onUpdate: onUpdateComment,
78
- onSelect: onSelectComment,
79
- }),
80
- ],
81
- }),
82
- [doc, accessor, themeMode],
83
- );
84
- useComments(view, id, commentRanges);
85
64
  useEffect(() => {
86
- if (view && !view.hasFocus && selectedValue !== selected) {
65
+ if (!view.current?.hasFocus && selectedValue !== selected) {
87
66
  setSelected(selectedValue);
88
67
  if (selectedValue) {
89
- focusComment(view, selectedValue);
68
+ focusComment(view.current!, selectedValue);
90
69
  }
91
70
  }
92
- }, [view, selected, commentRanges, selectedValue]);
71
+ }, [selected, commentRanges, selectedValue]);
72
+
73
+ useComments(view.current, id, commentRanges);
74
+
75
+ const extensions = useMemo(() => {
76
+ return [
77
+ comments({
78
+ onCreate: onCreateComment,
79
+ onDelete: onDeleteComment,
80
+ onUpdate: onUpdateComment,
81
+ onSelect: onSelectComment,
82
+ }),
83
+ ];
84
+ }, []);
85
+
86
+ if (!model) {
87
+ return null;
88
+ }
93
89
 
94
- return <div ref={parentRef} />;
90
+ // TODO(burdon): Highlight currently selected comment.
91
+ return <MarkdownEditor ref={view} model={model} extensions={extensions} />;
95
92
  };
96
93
 
97
94
  //
@@ -107,22 +104,8 @@ type StoryCommentThread = {
107
104
  };
108
105
 
109
106
  const StoryMessageBlock = (props: MessageBlockProps<{ text: TextObject }>) => {
110
- const { themeMode } = useThemeContext();
111
- const { doc, accessor } = useDocAccessor(props.block.text);
112
- const { parentRef } = useTextEditor(
113
- () => ({
114
- doc,
115
- extensions: [
116
- //
117
- createBasicExtensions(),
118
- createThemeExtensions({ themeMode }),
119
- automerge(accessor),
120
- ],
121
- }),
122
- [doc, accessor, themeMode],
123
- );
124
-
125
- return <div ref={parentRef} className='col-span-3' />;
107
+ const model = useTextModel({ text: props.block.text });
108
+ return model ? <TextEditor model={model} slots={{ root: { className: 'col-span-3' } }} /> : null;
126
109
  };
127
110
 
128
111
  const StoryThread: FC<{
@@ -131,32 +114,24 @@ const StoryThread: FC<{
131
114
  onSelect: () => void;
132
115
  onResolve: () => void;
133
116
  }> = ({ thread, selected, onSelect, onResolve }) => {
134
- const containerRef = useRef<HTMLDivElement>(null);
135
- const { themeMode } = useThemeContext();
117
+ const [autoFocus, setAutoFocus] = useState(false);
136
118
  const [item, setItem] = useState({ text: new TextObject() });
137
- const { doc, accessor } = useDocAccessor(item.text);
138
- const extensions = useMemo(
139
- () => [
140
- createBasicExtensions({ placeholder: 'Enter comment' }),
141
- createThemeExtensions({ themeMode }),
142
- automerge(accessor),
143
- ],
144
- [themeMode, accessor],
145
- );
119
+ const model = useTextModel({ text: item.text });
120
+ const editorRef = useRef<EditorView>(null);
121
+
122
+ const containerRef = useRef<HTMLDivElement>(null);
146
123
 
147
- const [autoFocus, setAutoFocus] = useState(false);
148
124
  useEffect(() => {
149
125
  if (selected) {
150
126
  containerRef.current?.scrollIntoView({ block: 'center', behavior: 'smooth' });
151
127
  if (thread.messages.length === 0) {
152
- // TODO(burdon): Causes thread to be reselected when loses focus.
153
128
  setAutoFocus(true);
154
129
  }
155
130
  }
156
131
  }, [selected]);
157
132
 
158
133
  const handleCreateMessage = () => {
159
- const text = getTextContent(item.text)?.trim();
134
+ const text = model?.text().trim();
160
135
  if (text?.length) {
161
136
  thread.messages.push({
162
137
  id: item.text.id,
@@ -168,6 +143,10 @@ const StoryThread: FC<{
168
143
  }
169
144
  };
170
145
 
146
+ if (!model) {
147
+ return null;
148
+ }
149
+
171
150
  return (
172
151
  <Thread current={selected} onClickCapture={onSelect}>
173
152
  <div className='col-start-2 flex gap-1 text-xs fg-description'>
@@ -176,7 +155,6 @@ const StoryThread: FC<{
176
155
  <span className='grow' />
177
156
  {!thread.cursor && <Trash />}
178
157
  </div>
179
-
180
158
  <ThreadHeading>
181
159
  {thread.range?.from} &ndash; {thread.range?.to}
182
160
  </ThreadHeading>
@@ -187,12 +165,11 @@ const StoryThread: FC<{
187
165
 
188
166
  <div ref={containerRef} className='contents'>
189
167
  <MessageTextbox
190
- id={item.text.id}
191
- doc={doc}
192
168
  authorId={authorId}
169
+ ref={editorRef}
193
170
  autoFocus={autoFocus}
194
- extensions={extensions}
195
171
  onEditorFocus={onSelect}
172
+ model={model}
196
173
  onSend={handleCreateMessage}
197
174
  />
198
175
  <ThreadFooter />
@@ -278,7 +255,7 @@ const Story = ({ text, autoCreate }: StoryProps) => {
278
255
  : [],
279
256
  },
280
257
  ]);
281
-
258
+ setSelected(id); // TODO(burdon): Not required.
282
259
  return id;
283
260
  };
284
261
 
@@ -324,10 +301,9 @@ const Story = ({ text, autoCreate }: StoryProps) => {
324
301
  }),
325
302
  );
326
303
 
327
- setSelected(current);
304
+ setSelected(current ?? closest);
328
305
  };
329
306
 
330
- // TODO(burdon): Focus switches to other thread.
331
307
  const handleSelectThread = (id: string) => {
332
308
  setSelected(id);
333
309
  };
@@ -385,3 +361,10 @@ export const Default = {
385
361
  text: document,
386
362
  },
387
363
  };
364
+
365
+ export const Testing = {
366
+ args: {
367
+ text: document,
368
+ autoCreate: true,
369
+ },
370
+ };
@@ -3,11 +3,11 @@
3
3
  //
4
4
 
5
5
  import '@dxosTheme';
6
- import React, { useMemo, useState } from 'react';
7
6
 
8
- import { setTextContent, TextObject } from '@dxos/echo-schema';
7
+ import React, { useState } from 'react';
8
+
9
9
  import { PublicKey } from '@dxos/keys';
10
- import { automerge, createBasicExtensions, createThemeExtensions, useDocAccessor } from '@dxos/react-ui-editor';
10
+ import { useInMemoryTextModel } from '@dxos/react-ui-editor';
11
11
  import { withTheme } from '@dxos/storybook-utils';
12
12
 
13
13
  import { Thread, ThreadFooter } from './Thread';
@@ -44,16 +44,14 @@ const Story = () => {
44
44
  },
45
45
  ]);
46
46
 
47
- const [item] = useState(new TextObject());
48
- const { accessor } = useDocAccessor(item);
49
- const extensions = useMemo(() => [createBasicExtensions(), createThemeExtensions(), automerge(accessor)], [accessor]);
47
+ const nextMessageModel = useInMemoryTextModel({ id: 't1__next' });
50
48
 
51
49
  // TODO(thure): Why does pressing Enter clear the text content?
52
50
  // Something to do with the in-memory text model perhaps?
53
51
  const handleSend = () => {
54
52
  setPending(true);
55
53
  setTimeout(() => {
56
- setTextContent(item, '');
54
+ nextMessageModel.setContent('');
57
55
  setPending(false);
58
56
  }, 2_000);
59
57
  };
@@ -63,13 +61,7 @@ const Story = () => {
63
61
  {messages.map((message) => (
64
62
  <Message key={message.id} {...message} />
65
63
  ))}
66
- <MessageTextbox
67
- id={item.id}
68
- authorId={identityKey1.toHex()}
69
- disabled={pending}
70
- extensions={extensions}
71
- onSend={handleSend}
72
- />
64
+ <MessageTextbox disabled={pending} authorId={identityKey1.toHex()} onSend={handleSend} model={nextMessageModel} />
73
65
  <ThreadFooter activity>Processing...</ThreadFooter>
74
66
  </Thread>
75
67
  );