Changeset View
Changeset View
Standalone View
Standalone View
web/chat/chat-input-bar.react.js
Show All 17 Lines | |||||
import { localIDPrefix, trimMessage } from 'lib/shared/message-utils'; | import { localIDPrefix, trimMessage } from 'lib/shared/message-utils'; | ||||
import { | import { | ||||
threadHasPermission, | threadHasPermission, | ||||
viewerIsMember, | viewerIsMember, | ||||
threadFrozenDueToViewerBlock, | threadFrozenDueToViewerBlock, | ||||
threadActualMembers, | threadActualMembers, | ||||
checkIfDefaultMembersAreVoiced, | checkIfDefaultMembersAreVoiced, | ||||
} from 'lib/shared/thread-utils'; | } from 'lib/shared/thread-utils'; | ||||
import { getTypeaheadUserSuggestions } from 'lib/shared/typeahead-utils'; | import { | ||||
getTypeaheadUserSuggestions, | |||||
getTypeaheadRegexMatches, | |||||
} from 'lib/shared/typeahead-utils'; | |||||
import type { TypeaheadMatchedStrings } from 'lib/shared/typeahead-utils'; | import type { TypeaheadMatchedStrings } from 'lib/shared/typeahead-utils'; | ||||
import type { CalendarQuery } from 'lib/types/entry-types'; | import type { CalendarQuery } from 'lib/types/entry-types'; | ||||
import type { LoadingStatus } from 'lib/types/loading-types'; | import type { LoadingStatus } from 'lib/types/loading-types'; | ||||
import { messageTypes } from 'lib/types/message-types'; | import { messageTypes } from 'lib/types/message-types'; | ||||
import { | import { | ||||
type ThreadInfo, | type ThreadInfo, | ||||
threadPermissions, | threadPermissions, | ||||
type ClientThreadJoinRequest, | type ClientThreadJoinRequest, | ||||
▲ Show 20 Lines • Show All 515 Lines • ▼ Show 20 Lines | function ConnectedChatInputBar(props) { | ||||
const calendarQuery = useSelector(nonThreadCalendarQuery); | const calendarQuery = useSelector(nonThreadCalendarQuery); | ||||
const dispatchActionPromise = useDispatchActionPromise(); | const dispatchActionPromise = useDispatchActionPromise(); | ||||
const callJoinThread = useServerCall(joinThread); | const callJoinThread = useServerCall(joinThread); | ||||
const userSearchIndex = useSelector(userStoreSearchIndex); | const userSearchIndex = useSelector(userStoreSearchIndex); | ||||
const threadMembers = useSelector( | const threadMembers = useSelector( | ||||
relativeMemberInfoSelectorForMembersOfThread(props.threadInfo.id), | relativeMemberInfoSelectorForMembersOfThread(props.threadInfo.id), | ||||
); | ); | ||||
const inputSliceEndingAtCursor = React.useMemo( | |||||
() => | |||||
props.inputState.draft.slice(0, props.inputState.textCursorPosition), | |||||
[props.inputState.draft, props.inputState.textCursorPosition], | |||||
); | |||||
// we only try to match if there is end of text or whitespace after cursor | |||||
const typeaheadRegexMatches = React.useMemo( | const typeaheadRegexMatches = React.useMemo( | ||||
() => | () => | ||||
inputSliceEndingAtCursor.length === props.inputState.draft.length || | getTypeaheadRegexMatches( | ||||
/\s/.test(props.inputState.draft[props.inputState.textCursorPosition]) | |||||
? inputSliceEndingAtCursor.match(webTypeaheadRegex) | |||||
: null, | |||||
[ | |||||
inputSliceEndingAtCursor, | |||||
props.inputState.textCursorPosition, | |||||
props.inputState.draft, | props.inputState.draft, | ||||
], | { | ||||
start: props.inputState.textCursorPosition, | |||||
end: props.inputState.textCursorPosition, | |||||
}, | |||||
webTypeaheadRegex, | |||||
), | |||||
[props.inputState.textCursorPosition, props.inputState.draft], | |||||
); | ); | ||||
const typeaheadMatchedStrings: ?TypeaheadMatchedStrings = React.useMemo( | const typeaheadMatchedStrings: ?TypeaheadMatchedStrings = React.useMemo( | ||||
() => | () => | ||||
typeaheadRegexMatches !== null | typeaheadRegexMatches !== null | ||||
? { | ? { | ||||
textBeforeAtSymbol: | textBeforeAtSymbol: | ||||
typeaheadRegexMatches.groups?.textPrefix ?? '', | typeaheadRegexMatches.groups?.textPrefix ?? '', | ||||
▲ Show 20 Lines • Show All 56 Lines • Show Last 20 Lines |