@dxos/react-ui-thread 0.4.8-main.a4c603b → 0.4.8-main.aa7abac

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,11 +72,10 @@ 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 { TextEditor, keymap, listener } from "@dxos/react-ui-editor";
75
+ import { keymap, listener, TextEditor } 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 } from "@dxos/util";
77
+ import { safeParseJson, hexToEmoji, hexToHue, isNotFalsy } from "@dxos/util";
78
78
  var avatarSize = 7;
79
- var messageCell = "plb-1 min-is-0";
80
79
  var MessageMeta = /* @__PURE__ */ forwardRef2(({ authorImgSrc, authorId, authorName, authorAvatarProps, continues = true, children, classNames, ...rootProps }, forwardedRef) => {
81
80
  return /* @__PURE__ */ React2.createElement(Avatar.Root, {
82
81
  size: avatarSize,
@@ -89,7 +88,7 @@ var MessageMeta = /* @__PURE__ */ forwardRef2(({ authorImgSrc, authorId, authorN
89
88
  ref: forwardedRef
90
89
  }, /* @__PURE__ */ React2.createElement("div", {
91
90
  role: "none",
92
- className: mx2("flex flex-col items-center gap-2", messageCell)
91
+ className: mx2("flex flex-col items-center gap-2 plb-2")
93
92
  }, /* @__PURE__ */ React2.createElement(Avatar.Frame, null, /* @__PURE__ */ React2.createElement(Avatar.Fallback, {
94
93
  text: authorAvatarProps?.emoji || hexToEmoji(authorId ?? "0")
95
94
  }), authorImgSrc && /* @__PURE__ */ React2.createElement(Avatar.Image, {
@@ -99,7 +98,7 @@ var MessageMeta = /* @__PURE__ */ forwardRef2(({ authorImgSrc, authorId, authorN
99
98
  className: "is-px grow surface-separator"
100
99
  })), /* @__PURE__ */ React2.createElement("div", {
101
100
  role: "none",
102
- className: messageCell
101
+ className: "plb-1 min-is-0"
103
102
  }, children)));
104
103
  });
105
104
  var DefaultMessageBlock = ({ block, onBlockDelete }) => {
@@ -152,65 +151,63 @@ var Message = (props) => {
152
151
  onBlockDelete: onDelete && (() => onDelete(id, i))
153
152
  }))));
154
153
  };
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;
167
- }
168
- }
169
- },
170
- {
171
- key: "Meta+Backspace",
172
- run: () => {
173
- if (onClear) {
174
- onClear();
175
- return true;
176
- } else {
177
- return false;
178
- }
179
- }
154
+ var keyBindings = ({ onSend, onClear }) => [
155
+ {
156
+ key: "Enter",
157
+ run: () => {
158
+ if (onSend) {
159
+ onSend();
160
+ return true;
161
+ } else {
162
+ return false;
180
163
  }
181
- ]),
182
- listener({
183
- onFocus: (focused) => {
184
- if (focused) {
185
- onEditorFocus?.();
186
- }
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;
187
175
  }
188
- })
189
- ], [
190
- _extensions,
191
- onSend,
192
- onClear,
193
- onEditorFocus
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?.();
191
+ }
192
+ }
193
+ })
194
+ ].filter(isNotFalsy);
195
+ }, [
196
+ _extensions
194
197
  ]);
195
198
  return /* @__PURE__ */ React2.createElement(MessageMeta, {
196
- id: editorProps.model.id,
199
+ id,
197
200
  authorId,
198
201
  authorName,
199
202
  authorImgSrc,
200
203
  authorAvatarProps,
201
204
  continues: false
202
205
  }, /* @__PURE__ */ React2.createElement(TextEditor, {
203
- slots: {
204
- root: {
205
- className: mx2("plb-0.5 mie-1 rounded-sm", focusRing, disabled && "opacity-50")
206
- }
207
- },
208
- readonly: disabled,
209
- extensions,
210
206
  ...editorProps,
211
- ref: forwardedRef
207
+ extensions,
208
+ className: mx2("plb-0.5 mie-1 rounded-sm", focusRing, disabled && "opacity-50")
212
209
  }));
213
- });
210
+ };
214
211
  export {
215
212
  Message,
216
213
  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\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": "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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", "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"]
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"]
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":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
+ {"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,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, type EditorView } from '@dxos/react-ui-editor';
3
+ import { type TextEditorProps } 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,15 +17,10 @@ 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;
20
21
  onSend?: () => void;
21
22
  onClear?: () => void;
22
23
  onEditorFocus?: () => void;
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>>;
24
+ } & MessageMetadata & TextEditorProps;
25
+ export declare const MessageTextbox: ({ id, onSend, onClear, onEditorFocus, authorId, authorName, authorImgSrc, authorAvatarProps, disabled, extensions: _extensions, ...editorProps }: MessageTextboxProps) => JSX.Element;
31
26
  //# 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;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"}
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"}
@@ -52,10 +52,4 @@ 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
- };
61
55
  //# 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,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
+ {"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 +1 @@
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"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-thread",
3
- "version": "0.4.8-main.a4c603b",
3
+ "version": "0.4.8-main.aa7abac",
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.a4c603b",
22
- "@dxos/react-ui-theme": "0.4.8-main.a4c603b",
23
- "@dxos/util": "0.4.8-main.a4c603b",
24
- "@dxos/react-ui-editor": "0.4.8-main.a4c603b",
25
- "@dxos/react-ui-mosaic": "0.4.8-main.a4c603b"
21
+ "@dxos/react-ui": "0.4.8-main.aa7abac",
22
+ "@dxos/react-ui-editor": "0.4.8-main.aa7abac",
23
+ "@dxos/react-ui-mosaic": "0.4.8-main.aa7abac",
24
+ "@dxos/react-ui-theme": "0.4.8-main.aa7abac",
25
+ "@dxos/util": "0.4.8-main.aa7abac"
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.a4c603b",
36
- "@dxos/keys": "0.4.8-main.a4c603b",
37
- "@dxos/random": "0.4.8-main.a4c603b",
38
- "@dxos/storybook-utils": "0.4.8-main.a4c603b",
39
- "@dxos/log": "0.4.8-main.a4c603b"
35
+ "@dxos/log": "0.4.8-main.aa7abac",
36
+ "@dxos/keys": "0.4.8-main.aa7abac",
37
+ "@dxos/echo-schema": "0.4.8-main.aa7abac",
38
+ "@dxos/random": "0.4.8-main.aa7abac",
39
+ "@dxos/storybook-utils": "0.4.8-main.aa7abac"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@phosphor-icons/react": "^2.0.5",
@@ -6,8 +6,9 @@ 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.
9
10
  import { Avatar, Button, type ThemedClassName, useTranslation } from '@dxos/react-ui';
10
- import { TextEditor, type TextEditorProps, keymap, type EditorView, listener } from '@dxos/react-ui-editor';
11
+ import { type TextEditorProps, keymap, listener, TextEditor } from '@dxos/react-ui-editor';
11
12
  import {
12
13
  focusRing,
13
14
  hoverableControlItem,
@@ -15,13 +16,12 @@ import {
15
16
  hoverableFocusedWithinControls,
16
17
  mx,
17
18
  } from '@dxos/react-ui-theme';
18
- import { safeParseJson, hexToEmoji, hexToHue } from '@dxos/util';
19
+ import { safeParseJson, hexToEmoji, hexToHue, isNotFalsy } from '@dxos/util';
19
20
 
20
21
  import { translationKey } from '../translations';
21
22
  import { type MessageEntity, type MessageEntityBlock, type MessageMetadata } from '../types';
22
23
 
23
24
  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', messageCell)}>
44
+ <div role='none' className={mx('flex flex-col items-center gap-2 plb-2')}>
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={messageCell}>
51
+ <div role='none' className='plb-1 min-is-0'>
52
52
  {children}
53
53
  </div>
54
54
  </div>
@@ -126,81 +126,73 @@ export const Message = <BlockValue,>(props: MessageProps<BlockValue>) => {
126
126
  };
127
127
 
128
128
  export type MessageTextboxProps = {
129
+ disabled?: boolean;
129
130
  onSend?: () => void;
130
131
  onClear?: () => void;
131
132
  onEditorFocus?: () => void;
132
- disabled?: boolean;
133
- } & Omit<MessageMetadata, 'id'> &
133
+ } & MessageMetadata &
134
134
  TextEditorProps;
135
135
 
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
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
+ }
149
146
  },
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
- );
189
-
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
147
  },
206
- );
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
+ }
158
+ },
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]);
188
+
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
+ };
@@ -7,22 +7,23 @@ 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 { TextObject } from '@dxos/echo-schema';
10
+ import { getTextContent, 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 } from '@dxos/react-ui';
14
+ import { Button, useThemeContext } from '@dxos/react-ui';
15
15
  import {
16
- MarkdownEditor,
17
16
  comments,
18
17
  type CommentsOptions,
19
18
  focusComment,
20
19
  useComments,
21
20
  type Comment,
22
21
  type Range,
23
- useTextModel,
24
- type EditorView,
25
- TextEditor,
22
+ useTextEditor,
23
+ createBasicExtensions,
24
+ createThemeExtensions,
25
+ automerge,
26
+ useDocAccessor,
26
27
  } from '@dxos/react-ui-editor';
27
28
  import { withTheme } from '@dxos/storybook-utils';
28
29
 
@@ -58,37 +59,39 @@ const Editor: FC<{
58
59
  onUpdateComment,
59
60
  onSelectComment,
60
61
  }) => {
61
- const model = useTextModel({ text: item.text });
62
- const view = useRef<EditorView>(null);
63
62
  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);
64
85
  useEffect(() => {
65
- if (!view.current?.hasFocus && selectedValue !== selected) {
86
+ if (view && !view.hasFocus && selectedValue !== selected) {
66
87
  setSelected(selectedValue);
67
88
  if (selectedValue) {
68
- focusComment(view.current!, selectedValue);
89
+ focusComment(view, selectedValue);
69
90
  }
70
91
  }
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
- }
92
+ }, [view, selected, commentRanges, selectedValue]);
89
93
 
90
- // TODO(burdon): Highlight currently selected comment.
91
- return <MarkdownEditor ref={view} model={model} extensions={extensions} />;
94
+ return <div ref={parentRef} />;
92
95
  };
93
96
 
94
97
  //
@@ -104,8 +107,22 @@ type StoryCommentThread = {
104
107
  };
105
108
 
106
109
  const StoryMessageBlock = (props: MessageBlockProps<{ text: TextObject }>) => {
107
- const model = useTextModel({ text: props.block.text });
108
- return model ? <TextEditor model={model} slots={{ root: { className: 'col-span-3' } }} /> : null;
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' />;
109
126
  };
110
127
 
111
128
  const StoryThread: FC<{
@@ -114,24 +131,32 @@ const StoryThread: FC<{
114
131
  onSelect: () => void;
115
132
  onResolve: () => void;
116
133
  }> = ({ thread, selected, onSelect, onResolve }) => {
117
- const [autoFocus, setAutoFocus] = useState(false);
118
- const [item, setItem] = useState({ text: new TextObject() });
119
- const model = useTextModel({ text: item.text });
120
- const editorRef = useRef<EditorView>(null);
121
-
122
134
  const containerRef = useRef<HTMLDivElement>(null);
135
+ const { themeMode } = useThemeContext();
136
+ 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
+ );
123
146
 
147
+ const [autoFocus, setAutoFocus] = useState(false);
124
148
  useEffect(() => {
125
149
  if (selected) {
126
150
  containerRef.current?.scrollIntoView({ block: 'center', behavior: 'smooth' });
127
151
  if (thread.messages.length === 0) {
152
+ // TODO(burdon): Causes thread to be reselected when loses focus.
128
153
  setAutoFocus(true);
129
154
  }
130
155
  }
131
156
  }, [selected]);
132
157
 
133
158
  const handleCreateMessage = () => {
134
- const text = model?.text().trim();
159
+ const text = getTextContent(item.text)?.trim();
135
160
  if (text?.length) {
136
161
  thread.messages.push({
137
162
  id: item.text.id,
@@ -143,10 +168,6 @@ const StoryThread: FC<{
143
168
  }
144
169
  };
145
170
 
146
- if (!model) {
147
- return null;
148
- }
149
-
150
171
  return (
151
172
  <Thread current={selected} onClickCapture={onSelect}>
152
173
  <div className='col-start-2 flex gap-1 text-xs fg-description'>
@@ -155,6 +176,7 @@ const StoryThread: FC<{
155
176
  <span className='grow' />
156
177
  {!thread.cursor && <Trash />}
157
178
  </div>
179
+
158
180
  <ThreadHeading>
159
181
  {thread.range?.from} &ndash; {thread.range?.to}
160
182
  </ThreadHeading>
@@ -165,11 +187,12 @@ const StoryThread: FC<{
165
187
 
166
188
  <div ref={containerRef} className='contents'>
167
189
  <MessageTextbox
190
+ id={item.text.id}
191
+ doc={doc}
168
192
  authorId={authorId}
169
- ref={editorRef}
170
193
  autoFocus={autoFocus}
194
+ extensions={extensions}
171
195
  onEditorFocus={onSelect}
172
- model={model}
173
196
  onSend={handleCreateMessage}
174
197
  />
175
198
  <ThreadFooter />
@@ -255,7 +278,7 @@ const Story = ({ text, autoCreate }: StoryProps) => {
255
278
  : [],
256
279
  },
257
280
  ]);
258
- setSelected(id); // TODO(burdon): Not required.
281
+
259
282
  return id;
260
283
  };
261
284
 
@@ -301,9 +324,10 @@ const Story = ({ text, autoCreate }: StoryProps) => {
301
324
  }),
302
325
  );
303
326
 
304
- setSelected(current ?? closest);
327
+ setSelected(current);
305
328
  };
306
329
 
330
+ // TODO(burdon): Focus switches to other thread.
307
331
  const handleSelectThread = (id: string) => {
308
332
  setSelected(id);
309
333
  };
@@ -361,10 +385,3 @@ export const Default = {
361
385
  text: document,
362
386
  },
363
387
  };
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';
6
7
 
7
- import React, { useState } from 'react';
8
-
8
+ import { setTextContent, TextObject } from '@dxos/echo-schema';
9
9
  import { PublicKey } from '@dxos/keys';
10
- import { useInMemoryTextModel } from '@dxos/react-ui-editor';
10
+ import { automerge, createBasicExtensions, createThemeExtensions, useDocAccessor } from '@dxos/react-ui-editor';
11
11
  import { withTheme } from '@dxos/storybook-utils';
12
12
 
13
13
  import { Thread, ThreadFooter } from './Thread';
@@ -44,14 +44,16 @@ const Story = () => {
44
44
  },
45
45
  ]);
46
46
 
47
- const nextMessageModel = useInMemoryTextModel({ id: 't1__next' });
47
+ const [item] = useState(new TextObject());
48
+ const { accessor } = useDocAccessor(item);
49
+ const extensions = useMemo(() => [createBasicExtensions(), createThemeExtensions(), automerge(accessor)], [accessor]);
48
50
 
49
51
  // TODO(thure): Why does pressing Enter clear the text content?
50
52
  // Something to do with the in-memory text model perhaps?
51
53
  const handleSend = () => {
52
54
  setPending(true);
53
55
  setTimeout(() => {
54
- nextMessageModel.setContent('');
56
+ setTextContent(item, '');
55
57
  setPending(false);
56
58
  }, 2_000);
57
59
  };
@@ -61,7 +63,13 @@ const Story = () => {
61
63
  {messages.map((message) => (
62
64
  <Message key={message.id} {...message} />
63
65
  ))}
64
- <MessageTextbox disabled={pending} authorId={identityKey1.toHex()} onSend={handleSend} model={nextMessageModel} />
66
+ <MessageTextbox
67
+ id={item.id}
68
+ authorId={identityKey1.toHex()}
69
+ disabled={pending}
70
+ extensions={extensions}
71
+ onSend={handleSend}
72
+ />
65
73
  <ThreadFooter activity>Processing...</ThreadFooter>
66
74
  </Thread>
67
75
  );