diff --git a/.changeset/sharp-eels-study.md b/.changeset/sharp-eels-study.md new file mode 100644 index 00000000000..54d2b99f904 --- /dev/null +++ b/.changeset/sharp-eels-study.md @@ -0,0 +1,7 @@ +--- +'@primer/react': minor +--- + +Adds onSelectSuggestion callback to + + diff --git a/src/drafts/InlineAutocomplete/InlineAutocomplete.docs.json b/src/drafts/InlineAutocomplete/InlineAutocomplete.docs.json index e4d8c06dabd..eaded29db28 100644 --- a/src/drafts/InlineAutocomplete/InlineAutocomplete.docs.json +++ b/src/drafts/InlineAutocomplete/InlineAutocomplete.docs.json @@ -19,6 +19,12 @@ "required": true, "description": "Register the triggers that can cause suggestions to appear." }, + { + "name": "onSelectSuggestion", + "type": "(event: SelectSuggestionsEvent) => void", + "defaultValue": "", + "description": "Called when a suggestion is selected. This should be used only for performing side effects, not for modifying\nthe inserted text. Do not call `setState` in this handler or the user's cursor\nposition / undo history could be lost." + }, { "name": "onShowSuggestions", "type": "(event: ShowSuggestionsEvent) => void", diff --git a/src/drafts/InlineAutocomplete/InlineAutocomplete.features.stories.tsx b/src/drafts/InlineAutocomplete/InlineAutocomplete.features.stories.tsx index 3f2f9c5a6ae..96ae45e30d1 100644 --- a/src/drafts/InlineAutocomplete/InlineAutocomplete.features.stories.tsx +++ b/src/drafts/InlineAutocomplete/InlineAutocomplete.features.stories.tsx @@ -56,6 +56,36 @@ export const SingleLine = ({loading, tabInserts}: ArgProps) => { ) } +export const OnSelectSuggestion = ({loading, tabInserts}: ArgProps) => { + const [suggestions, setSuggestions] = useState(null) + + const onShowSuggestions = (event: ShowSuggestionsEvent) => { + if (loading) { + setSuggestions('loading') + return + } + + setSuggestions(filteredUsers(event.query).map(user => user.login)) + } + + return ( + + Inline Autocomplete Demo + Try typing '@' to show user suggestions. + window.alert(`Selected ${suggestion}`)} + suggestions={suggestions} + onShowSuggestions={onShowSuggestions} + onHideSuggestions={() => setSuggestions(null)} + tabInsertsSuggestions={tabInserts} + > + + + + ) +} + const UserSuggestion = ({user, ...props}: {user: User} & ActionListItemProps) => ( diff --git a/src/drafts/InlineAutocomplete/InlineAutocomplete.tsx b/src/drafts/InlineAutocomplete/InlineAutocomplete.tsx index cb49434177b..484fd8631a5 100644 --- a/src/drafts/InlineAutocomplete/InlineAutocomplete.tsx +++ b/src/drafts/InlineAutocomplete/InlineAutocomplete.tsx @@ -6,6 +6,7 @@ import {useSyntheticChange} from '../hooks/useSyntheticChange' import {getAbsoluteCharacterCoordinates} from '../utils/character-coordinates' import { + SelectSuggestionsEvent, ShowSuggestionsEvent, Suggestions, SuggestionsPlacement, @@ -27,6 +28,16 @@ export type InlineAutocompleteProps = { * `suggestions` prop accordingly. */ onShowSuggestions: (event: ShowSuggestionsEvent) => void + + /** + * Called when a suggestion is selected. + * + * @note This should be used only for performing side effects, not for modifying + * the inserted text. Do not call `setState` in this handler or the user's cursor + * position / undo history could be lost. + */ + onSelectSuggestion?: (event: SelectSuggestionsEvent) => void + /** Called when suggestions should be hidden. Set `suggestions` to `null` in this case. */ onHideSuggestions: () => void /** @@ -96,6 +107,7 @@ const InlineAutocomplete = ({ suggestions, onShowSuggestions, onHideSuggestions, + onSelectSuggestion, sx, children, tabInsertsSuggestions = false, @@ -165,6 +177,8 @@ const InlineAutocomplete = ({ if (!inputRef.current || !showEventRef.current) return const {query, trigger} = showEventRef.current + onSelectSuggestion?.({suggestion, trigger, query}) + const currentCaretPosition = getSelectionStart(inputRef.current) ?? 0 const deleteLength = query.length + trigger.triggerChar.length const startIndex = currentCaretPosition - deleteLength @@ -186,7 +200,7 @@ const InlineAutocomplete = ({ }) /** - * Even thoughn we apply all the aria attributes, screen readers don't fully support this + * Even though we apply all the aria attributes, screen readers don't fully support this * dynamic use case and so they don't have a native way to indicate to the user when * there are suggestions available. So we use some hidden text with aria-live to politely * indicate what's available and how to use it. diff --git a/src/drafts/InlineAutocomplete/types.ts b/src/drafts/InlineAutocomplete/types.ts index 2c4d22fb4f9..2b7334d1c26 100644 --- a/src/drafts/InlineAutocomplete/types.ts +++ b/src/drafts/InlineAutocomplete/types.ts @@ -16,6 +16,11 @@ export type Trigger = { keepTriggerCharOnCommit?: boolean } +export type SelectSuggestionsEvent = ShowSuggestionsEvent & { + /** The suggestion that was selected. */ + suggestion: Suggestion +} + export type ShowSuggestionsEvent = { /** The trigger that caused this query. */ trigger: Trigger