121 | )
122 | }
123 | }
124 |
125 | export default MenuStatus
126 |
--------------------------------------------------------------------------------
/other/MAINTAINING.md:
--------------------------------------------------------------------------------
1 | # Maintaining
2 |
3 |
4 |
5 | **Table of Contents**
6 |
7 | - [Code of Conduct](#code-of-conduct)
8 | - [Issues](#issues)
9 | - [Pull Requests](#pull-requests)
10 | - [Release](#release)
11 | - [Thanks!](#thanks)
12 |
13 |
14 |
15 | This is documentation for maintainers of this project.
16 |
17 | ## Code of Conduct
18 |
19 | Please review, understand, and be an example of it. Violations of the code of conduct are
20 | taken seriously, even (especially) for maintainers.
21 |
22 | ## Issues
23 |
24 | We want to support and build the community. We do that best by helping people learn to solve
25 | their own problems. We have an issue template and hopefully most folks follow it. If it's
26 | not clear what the issue is, invite them to create a minimal reproduction of what they're trying
27 | to accomplish or the bug they think they've found.
28 |
29 | Once it's determined that a code change is necessary, point people to
30 | [makeapullrequest.com](http://makeapullrequest.com) and invite them to make a pull request.
31 | If they're the one who needs the feature, they're the one who can build it. If they need
32 | some hand holding and you have time to lend a hand, please do so. It's an investment into
33 | another human being, and an investment into a potential maintainer.
34 |
35 | Remember that this is open source, so the code is not yours, it's ours. If someone needs a change
36 | in the codebase, you don't have to make it happen yourself. Commit as much time to the project
37 | as you want/need to. Nobody can ask any more of you than that.
38 |
39 | ## Pull Requests
40 |
41 | As a maintainer, you're fine to make your branches on the main repo or on your own fork. Either
42 | way is fine.
43 |
44 | When we receive a pull request, a travis build is kicked off automatically (see the `.travis.yml`
45 | for what runs in the travis build). We avoid merging anything that breaks the travis build.
46 |
47 | Please review PRs and focus on the code rather than the individual. You never know when this is
48 | someone's first ever PR and we want their experience to be as positive as possible, so be
49 | uplifting and constructive.
50 |
51 | When you merge the pull request, 99% of the time you should use the
52 | [Squash and merge](https://help.github.com/articles/merging-a-pull-request/) feature. This keeps
53 | our git history clean, but more importantly, this allows us to make any necessary changes to the
54 | commit message so we release what we want to release. See the next section on Releases for more
55 | about that.
56 |
57 | ## Release
58 |
59 | Our releases are automatic. They happen whenever code lands into `master`. A travis build gets
60 | kicked off and if it's successful, a tool called
61 | [`semantic-release`](https://github.com/semantic-release/semantic-release) is used to
62 | automatically publish a new release to npm as well as a changelog to GitHub. It is only able to
63 | determine the version and whether a release is necessary by the git commit messages. With this
64 | in mind, **please brush up on [the commit message convention][commit] which drives our releases.**
65 |
66 | > One important note about this: Please make sure that commit messages do NOT contain the words
67 | > "BREAKING CHANGE" in them unless we want to push a major version. I've been burned by this
68 | > more than once where someone will include "BREAKING CHANGE: None" and it will end up releasing
69 | > a new major version. Not a huge deal honestly, but kind of annoying...
70 |
71 | ## Thanks!
72 |
73 | Thank you so much for helping to maintain this project!
74 |
75 | [commit]: https://github.com/conventional-changelog-archived-repos/conventional-changelog-angular/blob/ed32559941719a130bb0327f886d6a32a8cbc2ba/convention.md
76 |
--------------------------------------------------------------------------------
/src/input.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | import {AUTOCOMPLETE_CONTEXT} from './constants'
5 | import {compose, moveCursorToTheEnd} from './utils'
6 |
7 | class Input extends Component {
8 | static contextTypes = {
9 | [AUTOCOMPLETE_CONTEXT]: PropTypes.object.isRequired,
10 | }
11 | static ignoreKeys = ['Shift', 'Meta', 'Alt', 'Control']
12 | static propTypes = {
13 | onChange: PropTypes.func,
14 | onKeyDown: PropTypes.func,
15 | onBlur: PropTypes.func,
16 | getValue: PropTypes.func,
17 | defaultValue: PropTypes.string,
18 | }
19 | static defaultProps = {
20 | getValue: i => String(i),
21 | }
22 | constructor(props, context) {
23 | super(props, context)
24 | this.autocomplete = this.context[AUTOCOMPLETE_CONTEXT]
25 | this.autocomplete.input = this
26 | this.handleChange = compose(this.handleChange, this.props.onChange)
27 | this.handleKeyDown = compose(this.handleKeyDown, this.props.onKeyDown)
28 | this.handleBlur = compose(this.handleBlur, this.props.onBlur)
29 | }
30 |
31 | keyDownHandlers = {
32 | ArrowDown(event) {
33 | event.preventDefault()
34 | const amount = event.shiftKey ? 5 : 1
35 | this.autocomplete.moveHighlightedIndex(amount)
36 | },
37 |
38 | ArrowUp(event) {
39 | event.preventDefault()
40 | const amount = event.shiftKey ? -5 : -1
41 | this.autocomplete.moveHighlightedIndex(amount)
42 | },
43 |
44 | Enter(event) {
45 | event.preventDefault()
46 | this.autocomplete.selectHighlightedItem()
47 | },
48 |
49 | Escape(event) {
50 | event.preventDefault()
51 | this.autocomplete.reset()
52 | },
53 | }
54 |
55 | handleKeyDown = event => {
56 | if (event.key && this.keyDownHandlers[event.key]) {
57 | this.keyDownHandlers[event.key].call(this, event)
58 | } else if (!Input.ignoreKeys.includes(event.key)) {
59 | this.autocomplete.open()
60 | this.autocomplete.highlightIndex(
61 | this.autocomplete.state.menu.props.defaultHighlightedIndex,
62 | )
63 | }
64 | }
65 |
66 | handleChange = event => {
67 | this.updateInputValue(event.target.value)
68 | }
69 |
70 | handleBlur = () => {
71 | if (!this.autocomplete.isMouseDown) {
72 | this.autocomplete.reset()
73 | }
74 | }
75 |
76 | reset = () => {
77 | moveCursorToTheEnd(this._inputNode)
78 | }
79 |
80 | focusInput = () => {
81 | this._inputNode.focus()
82 | }
83 |
84 | getValue = item => {
85 | return item ? this.props.getValue(item) : null
86 | }
87 |
88 | componentWillUnmount() {
89 | if (this.autocomplete.input === this) {
90 | this.autocomplete.input = null
91 | }
92 | }
93 |
94 | componentDidMount() {
95 | if (this.props.defaultValue) {
96 | this.updateInputValue(this.props.defaultValue)
97 | }
98 | }
99 |
100 | updateInputValue(value) {
101 | if (this.autocomplete.state.inputValue !== value) {
102 | this.autocomplete.setState({
103 | inputValue: value,
104 | })
105 | }
106 | }
107 |
108 | render() {
109 | // eslint-disable-next-line no-unused-vars
110 | const {defaultValue, getValue, ...rest} = this.props
111 | const {inputValue, selectedItem, isOpen} = this.autocomplete.state
112 | const selectedItemValue = this.getValue(selectedItem)
113 | return (
114 | (this._inputNode = node)}
125 | />
126 | )
127 | }
128 | }
129 |
130 | export default Input
131 |
--------------------------------------------------------------------------------
/other/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 |
4 |
5 | **Table of Contents**
6 |
7 | - [Our Pledge](#our-pledge)
8 | - [Our Standards](#our-standards)
9 | - [Our Responsibilities](#our-responsibilities)
10 | - [Scope](#scope)
11 | - [Enforcement](#enforcement)
12 | - [Attribution](#attribution)
13 |
14 |
15 |
16 | ## Our Pledge
17 |
18 | In the interest of fostering an open and welcoming environment, we as
19 | contributors and maintainers pledge to making participation in our project and
20 | our community a harassment-free experience for everyone, regardless of age, body
21 | size, disability, ethnicity, gender identity and expression, level of experience,
22 | nationality, personal appearance, race, religion, or sexual identity and
23 | orientation.
24 |
25 | ## Our Standards
26 |
27 | Examples of behavior that contributes to creating a positive environment
28 | include:
29 |
30 | * Using welcoming and inclusive language
31 | * Being respectful of differing viewpoints and experiences
32 | * Gracefully accepting constructive criticism
33 | * Focusing on what is best for the community
34 | * Showing empathy towards other community members
35 |
36 | Examples of unacceptable behavior by participants include:
37 |
38 | * The use of sexualized language or imagery and unwelcome sexual attention or
39 | advances
40 | * Trolling, insulting/derogatory comments, and personal or political attacks
41 | * Public or private harassment
42 | * Publishing others' private information, such as a physical or electronic
43 | address, without explicit permission
44 | * Other conduct which could reasonably be considered inappropriate in a
45 | professional setting
46 |
47 | ## Our Responsibilities
48 |
49 | Project maintainers are responsible for clarifying the standards of acceptable
50 | behavior and are expected to take appropriate and fair corrective action in
51 | response to any instances of unacceptable behavior.
52 |
53 | Project maintainers have the right and responsibility to remove, edit, or
54 | reject comments, commits, code, wiki edits, issues, and other contributions
55 | that are not aligned to this Code of Conduct, or to ban temporarily or
56 | permanently any contributor for other behaviors that they deem inappropriate,
57 | threatening, offensive, or harmful.
58 |
59 | ## Scope
60 |
61 | This Code of Conduct applies both within project spaces and in public spaces
62 | when an individual is representing the project or its community. Examples of
63 | representing a project or community include using an official project e-mail
64 | address, posting via an official social media account, or acting as an appointed
65 | representative at an online or offline event. Representation of a project may be
66 | further defined and clarified by project maintainers.
67 |
68 | ## Enforcement
69 |
70 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
71 | reported by contacting the project team at kent+coc@doddsfamily.us. All
72 | complaints will be reviewed and investigated and will result in a response that
73 | is deemed necessary and appropriate to the circumstances. The project team is
74 | obligated to maintain confidentiality with regard to the reporter of an incident.
75 | Further details of specific enforcement policies may be posted separately.
76 |
77 | Project maintainers who do not follow or enforce the Code of Conduct in good
78 | faith may face temporary or permanent repercussions as determined by other
79 | members of the project's leadership.
80 |
81 | ## Attribution
82 |
83 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
84 | available at [http://contributor-covenant.org/version/1/4][version]
85 |
86 | [homepage]: http://contributor-covenant.org
87 | [version]: http://contributor-covenant.org/version/1/4/
88 |
--------------------------------------------------------------------------------
/examples/pages/basic/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 | import glamorous, {Div} from 'glamorous'
3 | import Autocomplete from '../../other/react-autocompletely'
4 |
5 | class Examples extends Component {
6 | state = {
7 | selectedColor: '',
8 | }
9 |
10 | changeHandler(selectedColor) {
11 | this.setState({selectedColor})
12 | }
13 |
14 | render() {
15 | const items = ['Black', 'Red', 'Green', 'Blue', 'Orange', 'Purple']
16 | return (
17 |
6 |
7 |
8 |
9 | [![Build Status][build-badge]][build]
10 | [![Code Coverage][coverage-badge]][coverage]
11 | [![version][version-badge]][package]
12 | [![downloads][downloads-badge]][npmcharts]
13 | [![MIT License][license-badge]][LICENSE]
14 |
15 | [](#contributors)
16 | [![PRs Welcome][prs-badge]][prs]
17 | [![Code of Conduct][coc-badge]][coc]
18 |
19 | [![Watch on GitHub][github-watch-badge]][github-watch]
20 | [![Star on GitHub][github-star-badge]][github-star]
21 | [![Tweet][twitter-badge]][twitter]
22 |
23 | ## The problem
24 |
25 | You need an autocomplete experience in your application and you want it to be
26 | accessible. You also want it to be simple and flexible to account for your use
27 | cases.
28 |
29 | ## This solution
30 |
31 | This is a collection of primitive components that you can compose together to
32 | create an autocomplete component which you can reuse in your application. It's
33 | based on ideas from the talk ["Compound Components"][compound-components-talk]
34 | which effectively gives you maximum flexibility with a minimal API because you
35 | are responsible for the rendering of the autocomplete components.
36 |
37 | This differs from other solutions which render things for their use case and
38 | then expose many options to allow for extensibility causing an API that is less
39 | easy to use and less flexible as well as making the implementation more
40 | complicated and harder to contribute to.
41 |
42 | ## Installation
43 |
44 | **This component is currently under development and is not yet released...**
45 |
46 | This module is distributed via [npm][npm] which is bundled with [node][node] and
47 | should be installed as one of your project's `dependencies`:
48 |
49 | ```
50 | npm install --save react-autocompletely
51 | ```
52 |
53 | > This package also depends on `react` and `prop-types`. Please make sure you have
54 | > those installed as well.
55 |
56 | ## Usage
57 |
58 | **Things are still in flux a little bit (looking for feedback).**
59 |
60 | ```jsx
61 | import Autocomplete from 'react-autocompletely'
62 |
63 | // use components together here.
64 | ```
65 |
66 | Available components and relevant props:
67 |
68 | ### Autocomplete
69 |
70 | This is the main component. It renders a `div` and forwards props. Wrap
71 | everything in this.
72 |
73 | #### onChange
74 |
75 | > `function(item: any)` | *required*
76 |
77 | Called when the user selects an item
78 |
79 | ### Autocomplete.Input
80 |
81 | This is the input component. It renders an `input` and forwards props.
82 |
83 | #### defaultValue
84 |
85 | > `string` / `null` | *defaults to null*
86 |
87 | The initial value the input should have when it's mounted.
88 |
89 | #### getValue
90 |
91 | > `function(item: any)` | defaults to an identity function (`i => String(i)`)
92 |
93 | Used to determine the `inputValue` for the selected item.
94 |
95 | ### Autocomplete.Controller
96 |
97 | This component allows you to receive and interact with the state of the
98 | autocomplete component.
99 |
100 | #### children
101 |
102 | > `function({})` | *required*
103 |
104 | This is called with an object with the properties listed below:
105 |
106 |
107 |
108 | | property | type | description |
109 | |-------------------------|----------------------------|------------------------------------------------------------------------------------------------------------------|
110 | | `highlightedIndex` | `number` / `null` | the currently highlighted item |
111 | | `setHighlightedIndex` | `function(index: number)` | call to set a new highlighted index |
112 | | `inputValue` | `string` / `null` | the current value of the input |
113 | | `isOpen` | `boolean` | the menu open state |
114 | | `toggleMenu` | `function(state: boolean)` | toggle the menu open state (if `state` is not provided, then it will be set to the inverse of the current state) |
115 | | `openMenu` | `function()` | opens the menu |
116 | | `closeMenu` | `function()` | closes the menu |
117 | | `selectedItem` | `any` | the currently selected item |
118 | | `clearSelection` | `function()` | clears the selection |
119 | | `selectItem` | `function(item: any)` | selects the given item |
120 | | `selectItemAtIndex` | `function(index: number)` | selects the item at the given index |
121 | | `selectHighlightedItem` | `function()` | selects the item that is currently highlighted |
122 |
123 | ### Autocomplete.Menu
124 |
125 | This component allows you to render the items based on the user input. It
126 | renders a `div` with another `div` for your items and a `div` for the menu
127 | status (for accessibility purposes)
128 |
129 | #### defaultHighlightedIndex
130 |
131 | > `number`/`null` | defaults to `null`
132 |
133 | This is the initial index to highlight when the menu first opens.
134 |
135 | #### children
136 |
137 | > `function({})` | *required*
138 |
139 | This is called with the same things that the `children` prop is called with for
140 | `Autocomplete.Controller`
141 |
142 | ### Autocomplete.Item
143 |
144 | Render your items inside this component. This renders a `div` and forwards all
145 | props.
146 |
147 | #### index
148 |
149 | > `number` | *required*
150 |
151 | this is how `react-autocompletely` keeps track of your item when updating the
152 | `highlightedIndex` as the user keys around.
153 |
154 | #### value
155 |
156 | > `any` | *required*
157 |
158 | This is the item data that will be selected when the user selects a particular
159 | item.
160 |
161 | ## Examples
162 |
163 | Examples exist on [codesandbox.io][examples]:
164 |
165 | - [react-autocompletely Apollo example](https://codesandbox.io/s/j2omZpK3W)
166 |
167 | If you would like to add an example, follow these steps:
168 |
169 | 1. Fork [this codesandbox](http://kcd.im/rac-example)
170 | 2. Update the code for your example (add some form of documentation to explain what it is)
171 | 3. Update the title and description
172 | 4. Add the tag: `react-autocompletely:example`
173 |
174 | ## Inspiration
175 |
176 | I was heavily inspired by [Ryan Florence][ryan] and his talk entitled:
177 | ["Compound Components"][compound-components-talk]. I also took a few ideas from
178 | the code in [`react-autocomplete`][react-autocomplete] and
179 | [jQuery UI's Autocomplete][jquery-complete].
180 |
181 | You can watch me build the first iteration of `react-autocompletely` on YouTube:
182 |
183 | - [Part 1](https://youtu.be/2kzD1IjDy5s)
184 | - [Part 2](https://youtu.be/w1Z7Jvj08_s)
185 |
186 | ## Other Solutions
187 |
188 | You can implement these other solutions using `react-autocompletely`, but if
189 | you'd prefer to use these out of the box solutions, then that's fine too:
190 |
191 | - [`react-select`](https://github.com/JedWatson/react-select)
192 | - [`react-autocomplete`](https://github.com/reactjs/react-autocomplete)
193 |
194 | ## Contributors
195 |
196 | Thanks goes to these people ([emoji key][emojis]):
197 |
198 |
199 | | [ Kent C. Dodds](https://kentcdodds.com) [💻](https://github.com/paypal/react-autocompletely/commits?author=kentcdodds "Code") [📖](https://github.com/paypal/react-autocompletely/commits?author=kentcdodds "Documentation") [🚇](#infra-kentcdodds "Infrastructure (Hosting, Build-Tools, etc)") [⚠️](https://github.com/paypal/react-autocompletely/commits?author=kentcdodds "Tests") | [ Jack Moore](https://github.com/jtmthf) [💡](#example-jtmthf "Examples") | [ Travis Arnold](http://travisrayarnold.com) [💻](https://github.com/paypal/react-autocompletely/commits?author=souporserious "Code") [📖](https://github.com/paypal/react-autocompletely/commits?author=souporserious "Documentation") | [ Jeremy Gayed](http://www.jeremygayed.com) [💡](#example-tizmagik "Examples") | [ Haroen Viaene](https://haroen.me) [💡](#example-Haroenv "Examples") | [ monssef](https://github.com/rezof) [💡](#example-rezof "Examples") | [ Federico Zivolo](https://fezvrasta.github.io) [📖](https://github.com/paypal/react-autocompletely/commits?author=FezVrasta "Documentation") |
200 | | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
201 | | [ Divyendu Singh](https://divyendusingh.com) [💡](#example-divyenduz "Examples") | [ Muhammad Salman](https://github.com/salmanmanekia) [💻](https://github.com/paypal/react-autocompletely/commits?author=salmanmanekia "Code") |
202 |
203 |
204 | This project follows the [all-contributors][all-contributors] specification.
205 | Contributions of any kind welcome!
206 |
207 | ## LICENSE
208 |
209 | MIT
210 |
211 | [npm]: https://www.npmjs.com/
212 | [node]: https://nodejs.org
213 | [build-badge]: https://img.shields.io/travis/paypal/react-autocompletely.svg?style=flat-square
214 | [build]: https://travis-ci.org/paypal/react-autocompletely
215 | [coverage-badge]: https://img.shields.io/codecov/c/github/paypal/react-autocompletely.svg?style=flat-square
216 | [coverage]: https://codecov.io/github/paypal/react-autocompletely
217 | [version-badge]: https://img.shields.io/npm/v/react-autocompletely.svg?style=flat-square
218 | [package]: https://www.npmjs.com/package/react-autocompletely
219 | [downloads-badge]: https://img.shields.io/npm/dm/react-autocompletely.svg?style=flat-square
220 | [npmcharts]: http://npmcharts.com/compare/react-autocompletely
221 | [license-badge]: https://img.shields.io/npm/l/react-autocompletely.svg?style=flat-square
222 | [license]: https://github.com/paypal/react-autocompletely/blob/master/LICENSE
223 | [prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
224 | [prs]: http://makeapullrequest.com
225 | [donate-badge]: https://img.shields.io/badge/$-support-green.svg?style=flat-square
226 | [coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
227 | [coc]: https://github.com/paypal/react-autocompletely/blob/master/other/CODE_OF_CONDUCT.md
228 | [github-watch-badge]: https://img.shields.io/github/watchers/paypal/react-autocompletely.svg?style=social
229 | [github-watch]: https://github.com/paypal/react-autocompletely/watchers
230 | [github-star-badge]: https://img.shields.io/github/stars/paypal/react-autocompletely.svg?style=social
231 | [github-star]: https://github.com/paypal/react-autocompletely/stargazers
232 | [twitter]: https://twitter.com/intent/tweet?text=Check%20out%20react-autocompletely!%20https://github.com/paypal/react-autocompletely%20%F0%9F%91%8D
233 | [twitter-badge]: https://img.shields.io/twitter/url/https/github.com/paypal/react-autocompletely.svg?style=social
234 | [emojis]: https://github.com/kentcdodds/all-contributors#emoji-key
235 | [all-contributors]: https://github.com/kentcdodds/all-contributors
236 | [ryan]: https://github.com/ryanflorence
237 | [compound-components-talk]: https://www.youtube.com/watch?v=hEGg-3pIHlE
238 | [react-autocomplete]: https://www.npmjs.com/package/react-autocomplete
239 | [jquery-complete]: https://jqueryui.com/autocomplete/
240 | [examples]: https://codesandbox.io/search?refinementList%5Btags%5D%5B0%5D=react-autocompletely%3Aexample&page=1
241 |
--------------------------------------------------------------------------------