Changeset View
Changeset View
Standalone View
Standalone View
web/utils/typeahead-utils.js
// @flow | // @flow | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { oldValidUsernameRegexString } from 'lib/shared/account-utils'; | import { oldValidUsernameRegexString } from 'lib/shared/account-utils'; | ||||
import { stringForUserExplicit } from 'lib/shared/user-utils'; | import { stringForUserExplicit } from 'lib/shared/user-utils'; | ||||
import type { RelativeMemberInfo } from 'lib/types/thread-types'; | import type { RelativeMemberInfo } from 'lib/types/thread-types'; | ||||
import { typeaheadStyle } from '../chat/chat-constants'; | import { typeaheadStyle } from '../chat/chat-constants'; | ||||
import { type InputState } from '../input/input-state'; | |||||
const webTypeaheadRegex: RegExp = new RegExp( | const webTypeaheadRegex: RegExp = new RegExp( | ||||
`(?<textPrefix>(?:^(?:.|\n)*\\s+)|^)@(?<username>${oldValidUsernameRegexString})?$`, | `(?<textPrefix>(?:^(?:.|\n)*\\s+)|^)@(?<username>${oldValidUsernameRegexString})?$`, | ||||
); | ); | ||||
export type TypeaheadTooltipAction = { | export type TypeaheadTooltipAction = { | ||||
+key: string, | +key: string, | ||||
+onClick: (SyntheticEvent<HTMLButtonElement>) => mixed, | +onClick: (SyntheticEvent<HTMLButtonElement>) => mixed, | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | offsetLeft + typeaheadStyle.tooltipWidth > textareaWidth | ||||
? textareaWidth - typeaheadStyle.tooltipWidth | ? textareaWidth - typeaheadStyle.tooltipWidth | ||||
: offsetLeft; | : offsetLeft; | ||||
return { | return { | ||||
caretTopOffset: offsetTop - textarea.scrollTop, | caretTopOffset: offsetTop - textarea.scrollTop, | ||||
caretLeftOffset, | caretLeftOffset, | ||||
}; | }; | ||||
} | } | ||||
export type GetTypeaheadTooltipActionsParams = { | |||||
+inputStateDraft: string, | |||||
+inputStateSetDraft: (draft: string) => mixed, | |||||
+inputStateSetTextCursorPosition: (newPosition: number) => mixed, | |||||
+suggestedUsers: $ReadOnlyArray<RelativeMemberInfo>, | |||||
+textBeforeAtSymbol: string, | |||||
+usernamePrefix: string, | |||||
}; | |||||
function getTypeaheadTooltipActions( | function getTypeaheadTooltipActions( | ||||
inputState: InputState, | params: GetTypeaheadTooltipActionsParams, | ||||
textarea: HTMLTextAreaElement, | |||||
suggestedUsers: $ReadOnlyArray<RelativeMemberInfo>, | |||||
textBeforeAtSymbol: string, | |||||
usernamePrefix: string, | |||||
): $ReadOnlyArray<TypeaheadTooltipAction> { | ): $ReadOnlyArray<TypeaheadTooltipAction> { | ||||
const { | |||||
inputStateDraft, | |||||
inputStateSetDraft, | |||||
inputStateSetTextCursorPosition, | |||||
suggestedUsers, | |||||
textBeforeAtSymbol, | |||||
usernamePrefix, | |||||
} = params; | |||||
return suggestedUsers | return suggestedUsers | ||||
.filter( | .filter( | ||||
suggestedUser => stringForUserExplicit(suggestedUser) !== 'anonymous', | suggestedUser => stringForUserExplicit(suggestedUser) !== 'anonymous', | ||||
) | ) | ||||
.map(suggestedUser => ({ | .map(suggestedUser => ({ | ||||
key: suggestedUser.id, | key: suggestedUser.id, | ||||
onClick: () => { | onClick: () => { | ||||
const newPrefixText = textBeforeAtSymbol; | const newPrefixText = textBeforeAtSymbol; | ||||
const totalMatchLength = | const totalMatchLength = | ||||
textBeforeAtSymbol.length + usernamePrefix.length + 1; // 1 for @ char | textBeforeAtSymbol.length + usernamePrefix.length + 1; // 1 for @ char | ||||
let newSuffixText = inputState.draft.slice(totalMatchLength); | let newSuffixText = inputStateDraft.slice(totalMatchLength); | ||||
newSuffixText = (newSuffixText[0] !== ' ' ? ' ' : '') + newSuffixText; | newSuffixText = (newSuffixText[0] !== ' ' ? ' ' : '') + newSuffixText; | ||||
const newText = | const newText = | ||||
newPrefixText + | newPrefixText + | ||||
'@' + | '@' + | ||||
stringForUserExplicit(suggestedUser) + | stringForUserExplicit(suggestedUser) + | ||||
newSuffixText; | newSuffixText; | ||||
inputState.setDraft(newText); | inputStateSetDraft(newText); | ||||
inputState.setTextCursorPosition( | inputStateSetTextCursorPosition( | ||||
newText.length - newSuffixText.length + 1, | newText.length - newSuffixText.length + 1, | ||||
); | ); | ||||
}, | }, | ||||
actionButtonContent: stringForUserExplicit(suggestedUser), | actionButtonContent: stringForUserExplicit(suggestedUser), | ||||
})); | })); | ||||
} | } | ||||
function getTypeaheadTooltipPosition( | function getTypeaheadTooltipPosition( | ||||
textarea: HTMLTextAreaElement, | textarea: HTMLTextAreaElement, | ||||
Show All 34 Lines |