diff --git a/lib/utils/entity-text.js b/lib/utils/entity-text.js --- a/lib/utils/entity-text.js +++ b/lib/utils/entity-text.js @@ -91,7 +91,18 @@ +hex: string, }; -type EntityTextComponent = UserEntity | ThreadEntity | ColorEntity | string; +type FarcasterUserEntity = { + +type: 'farcaster_user', + +fid: string, + +farcasterUsername?: ?string, +}; + +type EntityTextComponent = + | UserEntity + | ThreadEntity + | ColorEntity + | FarcasterUserEntity + | string; export type EntityText = $ReadOnlyArray; @@ -239,6 +250,12 @@ hex: input.hex, }); +type EntityTextFarcasterUserInput = { +fid: string }; +entityTextFunction.fcUser = (input: EntityTextFarcasterUserInput) => ({ + type: 'farcaster_user', + fid: input.fid, +}); + // ET is a JS tag function used in template literals, eg. ET`something` // It allows you to compose raw text and "entities" together type EntityTextFunction = (( @@ -248,6 +265,7 @@ +thread: EntityTextThreadInput => ThreadEntity, +user: EntityTextUserInput => UserEntity, +color: EntityTextColorInput => ColorEntity, + +fcUser: EntityTextFarcasterUserInput => FarcasterUserEntity, ... }; const ET: EntityTextFunction = entityTextFunction; @@ -335,6 +353,10 @@ return makePossessive({ str, isViewer }); } +function getNameForFarcasterUserEntity(entity: FarcasterUserEntity): string { + return entity.farcasterUsername ?? ''; +} + type EntityTextToRawStringParams = { +threadID?: ?string, +ignoreViewer?: ?boolean, @@ -355,6 +377,8 @@ return entity.hex; } else if (entity.type === 'user') { return getNameForUserEntity(entity, params?.ignoreViewer); + } else if (entity.type === 'farcaster_user') { + return getNameForFarcasterUserEntity(entity); } else { invariant( false, @@ -370,13 +394,20 @@ +renderThread: ({ +id: string, +name: string }) => React.Node, +renderUser: ({ +userID: string, +usernameText: string }) => React.Node, +renderColor: ({ +hex: string }) => React.Node, + +renderFarcasterUser: ({ +farcasterUsername: string }) => React.Node, }; function entityTextToReact( entityText: EntityText, threadID: string, renderFuncs: RenderFunctions, ): React.Node { - const { renderText, renderThread, renderUser, renderColor } = renderFuncs; + const { + renderText, + renderThread, + renderUser, + renderColor, + renderFarcasterUser, + } = renderFuncs; // ESLint doesn't recognize that invariant always throws // eslint-disable-next-line consistent-return return entityText.map((entity, i) => { @@ -414,6 +445,13 @@ {renderUser({ userID, usernameText })} ); + } else if (entity.type === 'farcaster_user') { + const name = getNameForFarcasterUserEntity(entity); + return ( + + {renderFarcasterUser({ farcasterUsername: name })} + + ); } else { invariant( false, @@ -446,6 +484,7 @@ | ThreadEntity | ColorEntity | TextEntity + | FarcasterUserEntity | ShadowUserEntity; function entityTextToObjects( entityText: EntityText, diff --git a/native/chat/inner-robotext-message.react.js b/native/chat/inner-robotext-message.react.js --- a/native/chat/inner-robotext-message.react.js +++ b/native/chat/inner-robotext-message.react.js @@ -77,6 +77,9 @@ ), renderColor: ({ hex }) => , + renderFarcasterUser: ({ farcasterUsername }) => ( + {farcasterUsername} + ), }); }, [resolvedRobotext, activeTheme, threadID, styles.robotext]); diff --git a/web/chat/robotext-message.react.js b/web/chat/robotext-message.react.js --- a/web/chat/robotext-message.react.js +++ b/web/chat/robotext-message.react.js @@ -71,6 +71,9 @@ ), renderColor: ({ hex }) => , + renderFarcasterUser: ({ farcasterUsername }) => ( + {farcasterUsername} + ), }); }, [resolvedRobotext, threadID]);