Skip to content

Commit

Permalink
<InlineAutocomplete>: Add onSelectSuggestion() callback to `<Inli…
Browse files Browse the repository at this point in the history
…neAutocomplete />` to allow execution of additional code after an autocomplete item was selected. (#3647)

* Allows to customize the replaced text onCommit

* Cleanup suggestion overwrite as this can be done by suggestion.value

* Cleanup comment

* Add changeset

* Add storyboard

* Update src/drafts/InlineAutocomplete/InlineAutocomplete.tsx

Co-authored-by: Ian Sanders <iansan5653@github.com>

* Introduce SelectSuggestionsEvent

* Update src/drafts/InlineAutocomplete/InlineAutocomplete.tsx

Co-authored-by: Ian Sanders <iansan5653@github.com>

* Update InlineAutocomplete.docs.json

* Update docs

* Update docs

* Update docs

---------

Co-authored-by: Ian Sanders <iansan5653@github.com>
Co-authored-by: Mike Perrotti <mperrotti@github.com>
  • Loading branch information
3 people authored Sep 6, 2023
1 parent d759fd3 commit e480a4a
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .changeset/sharp-eels-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@primer/react': minor
---

Adds onSelectSuggestion callback to <InlineAutocomplete />

<!-- Changed components: _none_ -->
6 changes: 6 additions & 0 deletions src/drafts/InlineAutocomplete/InlineAutocomplete.docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,36 @@ export const SingleLine = ({loading, tabInserts}: ArgProps) => {
)
}

export const OnSelectSuggestion = ({loading, tabInserts}: ArgProps) => {
const [suggestions, setSuggestions] = useState<Suggestions | null>(null)

const onShowSuggestions = (event: ShowSuggestionsEvent) => {
if (loading) {
setSuggestions('loading')
return
}

setSuggestions(filteredUsers(event.query).map(user => user.login))
}

return (
<FormControl>
<FormControl.Label>Inline Autocomplete Demo</FormControl.Label>
<FormControl.Caption>Try typing &apos;@&apos; to show user suggestions.</FormControl.Caption>
<InlineAutocomplete
triggers={[{triggerChar: '@'}]}
onSelectSuggestion={suggestion => window.alert(`Selected ${suggestion}`)}
suggestions={suggestions}
onShowSuggestions={onShowSuggestions}
onHideSuggestions={() => setSuggestions(null)}
tabInsertsSuggestions={tabInserts}
>
<TextInput sx={{lineHeight: 1.2}} />
</InlineAutocomplete>
</FormControl>
)
}

const UserSuggestion = ({user, ...props}: {user: User} & ActionListItemProps) => (
<ActionList.Item {...props}>
<ActionList.LeadingVisual>
Expand Down
16 changes: 15 additions & 1 deletion src/drafts/InlineAutocomplete/InlineAutocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {useSyntheticChange} from '../hooks/useSyntheticChange'
import {getAbsoluteCharacterCoordinates} from '../utils/character-coordinates'

import {
SelectSuggestionsEvent,
ShowSuggestionsEvent,
Suggestions,
SuggestionsPlacement,
Expand All @@ -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
/**
Expand Down Expand Up @@ -96,6 +107,7 @@ const InlineAutocomplete = ({
suggestions,
onShowSuggestions,
onHideSuggestions,
onSelectSuggestion,
sx,
children,
tabInsertsSuggestions = false,
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions src/drafts/InlineAutocomplete/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit e480a4a

Please sign in to comment.