Skip to content

Commit

Permalink
Add InlineAutocomplete component (#2157)
Browse files Browse the repository at this point in the history
* Add `useCombobox` hook, extending `@github/combobox-nav`

* Add `useSyntheticChange` hook

* Add `InlineAutocomplete` component

* Refactor and improve comments

* Remove extra type

* Add story and make it work with `FormControl`

* Add to main exports

* Add MDX file

* Remove unecessary ID on textarea in story

* Remove version-lock from new dependencies

* Make type of render function more specific

* Add unit tests

* Simplify `useCombobox` and use `navigate` to focus first item

Fixes not having an `aria-activedescendant` initially defined

* Fix tests by wrapping `userEvent.type` in `act`

* Fix preventing blur when tabbing from loading state

* Delete unused imports

* Change interfaces out for object types

* Add accessible live status message to describe suggestions

* Dynamically assign the combobox role to avoid treating the textarea as a combobox when no suggestions are available

* Shorten & revise status message

* Move to drafts

* Move docs to drafts

* Fix import in docs

* Update combobox-nav dependency

* Add option to control whether `Tab` key inserts suggestions

* Style the defaulted-to first option differently from the selected option

* Update combobox-nav dependency

* Update and fix unit tests

* Remove unused import (fix lint error)

* docs: add drafts metastring

* Remove `selectionVariant` from suggestions list

* Add `install:docs` script

* Add more examples to docs

* Add more stories

* Fix _another_ bug with the caret-coordinates utility and single-line inputs 🙃

* Move component & hooks to drafts folder

* Move stories & tests into drafts

* Remove non-null assertions in tests

* Move `textarea-caret` type declaration to `@types`

* Add props table

* Fix TS issue

* Create cuddly-bags-sort.md

Co-authored-by: Siddharth Kshetrapal <siddharthkp@github.com>
  • Loading branch information
iansan5653 and siddharthkp committed Aug 2, 2022
1 parent 885064e commit 77e7ab0
Show file tree
Hide file tree
Showing 20 changed files with 1,769 additions and 72 deletions.
5 changes: 5 additions & 0 deletions .changeset/cuddly-bags-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": patch
---

Add `InlineAutocomplete` component, `useCombobox` hook, and `useSyntheticChange` hook to drafts
Empty file added @types/@koddsson/index.d.ts
Empty file.
11 changes: 11 additions & 0 deletions @types/@koddsson/textarea-caret/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
declare module '@koddsson/textarea-caret' {
export interface CaretCoordinates {
top: number
left: number
height: number
}
export default function getCaretCoordinates(
input: HTMLTextAreaElement | HTMLInputElement,
index: number
): CaretCoordinates
}
162 changes: 162 additions & 0 deletions docs/content/drafts/InlineAutocomplete.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
---
title: InlineAutocomplete
componentId: inline_autocomplete
status: Draft
description: Provides inline auto completion suggestions for an input or textarea.
source: https://github.com/primer/react/tree/main/src/InlineAutocomplete
storybook: '/react/storybook?path=/story/forms-inlineautocomplete--default'
---

```js
import {InlineAutocomplete} from '@primer/react/drafts'
```

The `InlineAutocomplete` component extends an `Input` or `Textarea` component to provide inline suggestions, similar to those provided by a code editor.

## Examples

<Note variant="warning">

Input components **must always** be accompanied by a corresponding label to improve support for assistive
technologies. Examples below are provided for conciseness and may not reflect accessibility best practices.

`InlineAutocomplete` can be used with the [`FormControl`](/FormControl) component to render a corresponding label.

</Note>

### Multi-line input

Try typing a `#` symbol to see suggestions. Use `Enter` or click to apply a suggestion.

```javascript live noinline drafts
const options = ['javascript', 'typescript', 'css', 'html', 'webassembly']

const SimpleExample = () => {
const [suggestions, setSuggestions] = React.useState([])

return (
<InlineAutocomplete
triggers={[{triggerChar: '#'}]}
suggestions={suggestions}
onShowSuggestions={({query}) => setSuggestions(options.filter(tag => tag.includes(query)))}
onHideSuggestions={() => setSuggestions([])}
>
<Textarea />
</InlineAutocomplete>
)
}

render(SimpleExample)
```

### Single-line input

```javascript live noinline drafts
const options = ['javascript', 'typescript', 'css', 'html', 'webassembly']

const SimpleExample = () => {
const [suggestions, setSuggestions] = React.useState([])

return (
<InlineAutocomplete
triggers={[{triggerChar: '#'}]}
suggestions={suggestions}
onShowSuggestions={({query}) => setSuggestions(options.filter(tag => tag.includes(query)))}
onHideSuggestions={() => setSuggestions([])}
>
<TextInput />
</InlineAutocomplete>
)
}

render(SimpleExample)
```

### Labelled

```javascript live noinline drafts
const options = ['javascript', 'typescript', 'css', 'html', 'webassembly']

const SimpleExample = () => {
const [suggestions, setSuggestions] = React.useState([])

return (
<FormControl>
<FormControl.Label>Example</FormControl.Label>
<InlineAutocomplete
triggers={[{triggerChar: '#'}]}
suggestions={suggestions}
onShowSuggestions={({query}) => setSuggestions(options.filter(tag => tag.includes(query)))}
onHideSuggestions={() => setSuggestions([])}
>
<Textarea />
</InlineAutocomplete>
</FormControl>
)
}

render(SimpleExample)
```

## Props

<PropsTable>
<PropsTableRow
name="children"
required
type="React.ReactNode"
description="An `input` or `textarea` compatible component to extend. A compatible component is any component that forwards a ref and props to an underlying `input` or `textarea` element, including but not limited to `Input`, `TextArea`, `input`, `textarea`, `styled.input`, and `styled.textarea`. If the child is not compatible, a runtime `TypeError` will be thrown."
/>
<PropsTableRow
name="triggers"
required
type="Array<Trigger>"
description="Register the triggers that can cause suggestions to appear."
/>
<PropsTableRow
name="onShowSuggestions"
type="(event: ShowSuggestionsEvent) => void"
required
description="Called when a valid suggestion query is updated. This should be handled by setting the `suggestions` prop accordingly."
/>
<PropsTableRow
name="onShowSuggestions"
type="() => void"
required
description="Called when suggestions should be hidden. Set `suggestions` to `null` or an empty array in this case."
/>
<PropsTableRow
name="suggestions"
type="Suggestion[] | null | 'loading'"
required
description="The currently visible list of suggestions. If `loading`, a loading indicator will be shown. If `null` or empty, the list will be hidden. Suggestion sort will be preserved. Typically, this should not contain more than five or so suggestions."
/>
<PropsTableRow
name="tabInsertsSuggestions"
type="boolean"
defaultValue="false"
description="If `true`, suggestions will be applied with both `Tab` and `Enter`, instead of just `Enter`. This may be expected behavior for users used to IDEs, but use caution when hijacking browser tabbing capability."
/>
<PropsTableSxRow />
</PropsTable>

## Status

<ComponentChecklist
items={{
propsDocumented: false,
noUnnecessaryDeps: true,
adaptsToThemes: true,
adaptsToScreenSizes: true,
fullTestCoverage: false,
usedInProduction: true,
usageExamplesDocumented: false,
hasStorybookStories: false,
designReviewed: false,
a11yReviewed: false,
stableApi: false,
addressedApiFeedback: false,
hasDesignGuidelines: false,
hasFigmaComponent: false
}}
/>

0 comments on commit 77e7ab0

Please sign in to comment.