Page MenuHomePhorge

D8943.1765336331.diff
No OneTemporary

Size
12 KB
Referenced Files
None
Subscribers
None

D8943.1765336331.diff

diff --git a/web/chat/chat-input-bar.react.js b/web/chat/chat-input-bar.react.js
--- a/web/chat/chat-input-bar.react.js
+++ b/web/chat/chat-input-bar.react.js
@@ -17,8 +17,9 @@
getMentionTypeaheadUserSuggestions,
getTypeaheadRegexMatches,
getUserMentionsCandidates,
+ type MentionTypeaheadSuggestionItem,
+ type TypeaheadMatchedStrings,
} from 'lib/shared/mention-utils.js';
-import type { TypeaheadMatchedStrings } from 'lib/shared/mention-utils.js';
import { localIDPrefix, trimMessage } from 'lib/shared/message-utils.js';
import {
threadHasPermission,
@@ -35,7 +36,6 @@
type ThreadInfo,
type ClientThreadJoinRequest,
type ThreadJoinPayload,
- type RelativeMemberInfo,
} from 'lib/types/thread-types.js';
import { type UserInfos } from 'lib/types/user-types.js';
import {
@@ -56,7 +56,11 @@
import Multimedia from '../media/multimedia.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { nonThreadCalendarQuery } from '../selectors/nav-selectors.js';
-import { webMentionTypeaheadRegex } from '../utils/typeahead-utils.js';
+import {
+ webMentionTypeaheadRegex,
+ getMentionTypeaheadTooltipActions,
+ getMentionTypeaheadTooltipButtons,
+} from '../utils/typeahead-utils.js';
type BaseProps = {
+threadInfo: ThreadInfo,
@@ -74,7 +78,7 @@
+dispatchActionPromise: DispatchActionPromise,
+joinThread: (request: ClientThreadJoinRequest) => Promise<ThreadJoinPayload>,
+typeaheadMatchedStrings: ?TypeaheadMatchedStrings,
- +suggestedUsers: $ReadOnlyArray<RelativeMemberInfo>,
+ +suggestions: $ReadOnlyArray<MentionTypeaheadSuggestionItem>,
+parentThreadInfo: ?ThreadInfo,
};
@@ -364,7 +368,7 @@
let typeaheadTooltip;
if (
this.props.inputState.typeaheadState.canBeVisible &&
- this.props.suggestedUsers.length > 0 &&
+ this.props.suggestions.length > 0 &&
this.props.typeaheadMatchedStrings &&
this.textarea
) {
@@ -373,7 +377,9 @@
inputState={this.props.inputState}
textarea={this.textarea}
matchedStrings={this.props.typeaheadMatchedStrings}
- suggestedUsers={this.props.suggestedUsers}
+ suggestions={this.props.suggestions}
+ typeaheadTooltipActionsGetter={getMentionTypeaheadTooltipActions}
+ typeaheadTooltipButtonsGetter={getMentionTypeaheadTooltipButtons}
/>
);
}
@@ -621,23 +627,22 @@
props.inputState.typeaheadState.keepUpdatingThreadMembers,
]);
- const suggestedUsers: $ReadOnlyArray<RelativeMemberInfo> =
- React.useMemo(() => {
- if (!typeaheadMatchedStrings) {
- return [];
- }
- return getMentionTypeaheadUserSuggestions(
- userSearchIndex,
- props.inputState.typeaheadState.frozenUserMentionsCandidates,
- viewerID,
- typeaheadMatchedStrings.textPrefix,
- ).map(suggestion => suggestion.userInfo);
- }, [
+ const suggestedUsers = React.useMemo(() => {
+ if (!typeaheadMatchedStrings) {
+ return [];
+ }
+ return getMentionTypeaheadUserSuggestions(
userSearchIndex,
props.inputState.typeaheadState.frozenUserMentionsCandidates,
viewerID,
- typeaheadMatchedStrings,
- ]);
+ typeaheadMatchedStrings.textPrefix,
+ );
+ }, [
+ userSearchIndex,
+ props.inputState.typeaheadState.frozenUserMentionsCandidates,
+ viewerID,
+ typeaheadMatchedStrings,
+ ]);
return (
<ChatInputBar
@@ -652,7 +657,7 @@
dispatchActionPromise={dispatchActionPromise}
joinThread={callJoinThread}
typeaheadMatchedStrings={typeaheadMatchedStrings}
- suggestedUsers={suggestedUsers}
+ suggestions={suggestedUsers}
parentThreadInfo={parentThreadInfo}
/>
);
diff --git a/web/chat/typeahead-tooltip.react.js b/web/chat/typeahead-tooltip.react.js
--- a/web/chat/typeahead-tooltip.react.js
+++ b/web/chat/typeahead-tooltip.react.js
@@ -3,28 +3,47 @@
import classNames from 'classnames';
import * as React from 'react';
-import type { TypeaheadMatchedStrings } from 'lib/shared/mention-utils.js';
-import type { RelativeMemberInfo } from 'lib/types/thread-types.js';
+import type {
+ TypeaheadMatchedStrings,
+ TypeaheadTooltipActionItem,
+} from 'lib/shared/mention-utils.js';
import { leastPositiveResidue } from 'lib/utils/math-utils.js';
import css from './typeahead-tooltip.css';
import type { InputState } from '../input/input-state.js';
+import type {
+ GetTypeaheadTooltipActionsParams,
+ GetMentionTypeaheadTooltipButtonsParams,
+} from '../utils/typeahead-utils.js';
import {
getTypeaheadOverlayScroll,
- getTypeaheadTooltipActions,
- getTypeaheadTooltipButtons,
getTypeaheadTooltipPosition,
} from '../utils/typeahead-utils.js';
-export type TypeaheadTooltipProps = {
+export type TypeaheadTooltipProps<SuggestionItemType> = {
+inputState: InputState,
+textarea: HTMLTextAreaElement,
+matchedStrings: TypeaheadMatchedStrings,
- +suggestedUsers: $ReadOnlyArray<RelativeMemberInfo>,
+ +suggestions: $ReadOnlyArray<SuggestionItemType>,
+ +typeaheadTooltipActionsGetter: (
+ GetTypeaheadTooltipActionsParams<SuggestionItemType>,
+ ) => $ReadOnlyArray<TypeaheadTooltipActionItem<SuggestionItemType>>,
+ +typeaheadTooltipButtonsGetter: (
+ GetMentionTypeaheadTooltipButtonsParams<SuggestionItemType>,
+ ) => React.Node,
};
-function TypeaheadTooltip(props: TypeaheadTooltipProps): React.Node {
- const { inputState, textarea, matchedStrings, suggestedUsers } = props;
+function TypeaheadTooltip<SuggestionItemType>(
+ props: TypeaheadTooltipProps<SuggestionItemType>,
+): React.Node {
+ const {
+ inputState,
+ textarea,
+ matchedStrings,
+ suggestions,
+ typeaheadTooltipActionsGetter,
+ typeaheadTooltipButtonsGetter,
+ } = props;
const { textBeforeAtSymbol, textPrefix } = matchedStrings;
@@ -38,7 +57,7 @@
React.useEffect(() => {
setChosenPositionInOverlay(0);
- }, [suggestedUsers]);
+ }, [suggestions]);
React.useEffect(() => {
setIsVisibleForAnimation(true);
@@ -57,11 +76,11 @@
const actions = React.useMemo(
() =>
- getTypeaheadTooltipActions({
+ typeaheadTooltipActionsGetter({
inputStateDraft: inputState.draft,
inputStateSetDraft: inputState.setDraft,
inputStateSetTextCursorPosition: inputState.setTextCursorPosition,
- suggestedUsers,
+ suggestions,
textBeforeAtSymbol,
textPrefix,
}),
@@ -69,9 +88,10 @@
inputState.draft,
inputState.setDraft,
inputState.setTextCursorPosition,
- suggestedUsers,
+ suggestions,
textBeforeAtSymbol,
textPrefix,
+ typeaheadTooltipActionsGetter,
],
);
@@ -91,12 +111,12 @@
const tooltipButtons = React.useMemo(
() =>
- getTypeaheadTooltipButtons(
+ typeaheadTooltipButtonsGetter({
setChosenPositionInOverlay,
chosenPositionInOverlay,
actions,
- ),
- [setChosenPositionInOverlay, actions, chosenPositionInOverlay],
+ }),
+ [typeaheadTooltipButtonsGetter, chosenPositionInOverlay, actions],
);
const close = React.useCallback(() => {
@@ -164,7 +184,7 @@
}
}, [chosenPositionInOverlay]);
- if (suggestedUsers.length === 0) {
+ if (suggestions.length === 0) {
return null;
}
diff --git a/web/utils/typeahead-utils.js b/web/utils/typeahead-utils.js
--- a/web/utils/typeahead-utils.js
+++ b/web/utils/typeahead-utils.js
@@ -4,10 +4,13 @@
import * as React from 'react';
import { oldValidUsernameRegexString } from 'lib/shared/account-utils.js';
-import { getNewTextAndSelection } from 'lib/shared/mention-utils.js';
+import {
+ getNewTextAndSelection,
+ type MentionTypeaheadSuggestionItem,
+ type TypeaheadTooltipActionItem,
+} from 'lib/shared/mention-utils.js';
import { stringForUserExplicit } from 'lib/shared/user-utils.js';
import type { SetState } from 'lib/types/hook-types.js';
-import type { RelativeMemberInfo } from 'lib/types/thread-types.js';
import UserAvatar from '../avatars/user-avatar.react.js';
import { typeaheadStyle } from '../chat/chat-constants.js';
@@ -18,12 +21,6 @@
`(?<textPrefix>(?:^(?:.|\n)*\\s+)|^)@(?<username>${oldValidUsernameRegexString})?$`,
);
-export type TypeaheadTooltipAction = {
- +key: string,
- +execute: () => mixed,
- +actionButtonContent: { +userID: string, +username: string },
-};
-
export type TooltipPosition = {
+top: number,
+left: number,
@@ -76,55 +73,67 @@
caretLeftOffset,
};
}
-export type GetTypeaheadTooltipActionsParams = {
+export type GetTypeaheadTooltipActionsParams<SuggestionItemType> = {
+inputStateDraft: string,
+inputStateSetDraft: (draft: string) => mixed,
+inputStateSetTextCursorPosition: (newPosition: number) => mixed,
- +suggestedUsers: $ReadOnlyArray<RelativeMemberInfo>,
+ +suggestions: $ReadOnlyArray<SuggestionItemType>,
+textBeforeAtSymbol: string,
+textPrefix: string,
};
-function getTypeaheadTooltipActions(
- params: GetTypeaheadTooltipActionsParams,
-): $ReadOnlyArray<TypeaheadTooltipAction> {
+function getMentionTypeaheadTooltipActions(
+ params: GetTypeaheadTooltipActionsParams<MentionTypeaheadSuggestionItem>,
+): $ReadOnlyArray<TypeaheadTooltipActionItem<MentionTypeaheadSuggestionItem>> {
const {
inputStateDraft,
inputStateSetDraft,
inputStateSetTextCursorPosition,
- suggestedUsers,
+ suggestions,
textBeforeAtSymbol,
textPrefix,
} = params;
- return suggestedUsers
- .filter(
- suggestedUser => stringForUserExplicit(suggestedUser) !== 'anonymous',
- )
- .map(suggestedUser => ({
- key: suggestedUser.id,
- execute: () => {
- const { newText, newSelectionStart } = getNewTextAndSelection(
- textBeforeAtSymbol,
- inputStateDraft,
- textPrefix,
- stringForUserExplicit(suggestedUser),
- );
-
- inputStateSetDraft(newText);
- inputStateSetTextCursorPosition(newSelectionStart);
- },
- actionButtonContent: {
- userID: suggestedUser.id,
- username: stringForUserExplicit(suggestedUser),
- },
- }));
+ const actions = [];
+ for (const suggestion of suggestions) {
+ if (suggestion.type === 'user') {
+ const suggestedUser = suggestion.userInfo;
+ if (stringForUserExplicit(suggestedUser) === 'anonymous') {
+ continue;
+ }
+ const mentionText = `@${stringForUserExplicit(suggestedUser)}`;
+ actions.push({
+ key: suggestedUser.id,
+ execute: () => {
+ const { newText, newSelectionStart } = getNewTextAndSelection(
+ textBeforeAtSymbol,
+ inputStateDraft,
+ textPrefix,
+ mentionText,
+ );
+
+ inputStateSetDraft(newText);
+ inputStateSetTextCursorPosition(newSelectionStart);
+ },
+ actionButtonContent: {
+ type: 'user',
+ userInfo: suggestedUser,
+ },
+ });
+ }
+ }
+ return actions;
}
-function getTypeaheadTooltipButtons(
- setChosenPositionInOverlay: SetState<number>,
- chosenPositionInOverlay: number,
- actions: $ReadOnlyArray<TypeaheadTooltipAction>,
+export type GetMentionTypeaheadTooltipButtonsParams<SuggestionItemType> = {
+ +setChosenPositionInOverlay: SetState<number>,
+ +chosenPositionInOverlay: number,
+ +actions: $ReadOnlyArray<TypeaheadTooltipActionItem<SuggestionItemType>>,
+};
+function getMentionTypeaheadTooltipButtons(
+ params: GetMentionTypeaheadTooltipButtonsParams<MentionTypeaheadSuggestionItem>,
): $ReadOnlyArray<React.Node> {
+ const { setChosenPositionInOverlay, chosenPositionInOverlay, actions } =
+ params;
return actions.map((action, idx) => {
const { key, execute, actionButtonContent } = action;
const buttonClasses = classNames(css.suggestion, {
@@ -137,6 +146,16 @@
setChosenPositionInOverlay(idx);
};
+ let avatarComponent = null;
+ let typeaheadButtonText = null;
+ if (actionButtonContent.type === 'user') {
+ const suggestedUser = actionButtonContent.userInfo;
+ avatarComponent = (
+ <UserAvatar size="small" userID={actionButtonContent.userInfo.id} />
+ );
+ typeaheadButtonText = `@${stringForUserExplicit(suggestedUser)}`;
+ }
+
return (
<Button
key={key}
@@ -144,8 +163,8 @@
onMouseMove={onMouseMove}
className={buttonClasses}
>
- <UserAvatar size="small" userID={actionButtonContent.userID} />
- <span className={css.username}>@{actionButtonContent.username}</span>
+ {avatarComponent}
+ <span className={css.username}>{typeaheadButtonText}</span>
</Button>
);
});
@@ -208,8 +227,8 @@
export {
webMentionTypeaheadRegex,
getCaretOffsets,
- getTypeaheadTooltipActions,
- getTypeaheadTooltipButtons,
+ getMentionTypeaheadTooltipActions,
+ getMentionTypeaheadTooltipButtons,
getTypeaheadOverlayScroll,
getTypeaheadTooltipPosition,
};

File Metadata

Mime Type
text/plain
Expires
Wed, Dec 10, 3:12 AM (22 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5860356
Default Alt Text
D8943.1765336331.diff (12 KB)

Event Timeline