mirror of
https://github.com/fergalmoran/turnstone.git
synced 2025-12-22 09:49:56 +00:00
Expose DOM methods via a forwarded ref
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
### 1.4.0 (6 Apr 2022)
|
||||
- Expose DOM methods via a forwarded ref
|
||||
|
||||
### 1.3.0 (2 Apr 2022)
|
||||
- Extend listbox and defaultListbox prop types to allow functions returning a promise resolving to an array of group settings
|
||||
|
||||
|
||||
57
README.md
57
README.md
@@ -11,6 +11,7 @@ Turnstone is a highly customisable, easy-to-use autocomplete search component fo
|
||||
- [API](#api)
|
||||
- [Props](#props)
|
||||
- [Component Props](#component-props)
|
||||
- [Methods](#methods)
|
||||
- [Contributing](#contributing)
|
||||
- [Release Checklist](#release-checklist)
|
||||
- [License](#license)
|
||||
@@ -624,6 +625,62 @@ The following custom components can also be supplied as props:
|
||||
- **`id`** (string) The `id` of the group supplied in the `listbox` or `defaultListbox` prop.
|
||||
- **`index`** (number) The index of the group. Matches the order supplied in the `listbox` or `defaultListbox` prop. Zero-indexed.
|
||||
|
||||
### Methods
|
||||
|
||||
There are a number of methods accessible via a ref supplied to the Turnstone component.
|
||||
|
||||
For example:
|
||||
|
||||
```jsx
|
||||
import React, { useRef } from 'react'
|
||||
import Turnstone from 'turnstone'
|
||||
import data from './data'
|
||||
|
||||
const App = () => {
|
||||
const listbox = { data }
|
||||
|
||||
const turnstoneRef = useRef()
|
||||
|
||||
const handleQuery = () => {
|
||||
turnstoneRef.current?.query('new')
|
||||
}
|
||||
|
||||
const handleClear = () => {
|
||||
turnstoneRef.current?.clear()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Turnstone ref={turnstoneRef} listbox={listbox} />
|
||||
<button onClick={handleQuery}>Perform Query</button>
|
||||
<button onClick={handleClear}>Clear Contents</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The methods are as follows:
|
||||
|
||||
#### `blur()`
|
||||
|
||||
Removes keyboard focus from the search box.
|
||||
|
||||
#### `clear()`
|
||||
|
||||
Clears the contents of the search box
|
||||
|
||||
#### `focus()`
|
||||
|
||||
Sets keyboard focus on the search box.
|
||||
|
||||
#### `query(<string>)`
|
||||
|
||||
Sets the search box contents to the string argument supplied to the function.
|
||||
|
||||
#### `select()`
|
||||
|
||||
Selects the contents of the search box
|
||||
|
||||
## Contributing
|
||||
- Fork the project
|
||||
- Run the project in development mode: `$ npm run dev`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint no-console: 0 */
|
||||
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import React, { useCallback, useState, useRef } from 'react'
|
||||
import Turnstone from '../../src/lib'
|
||||
import styles from './styles/App.module.css'
|
||||
import autocompleteStyles from './styles/autocomplete.module.css'
|
||||
@@ -71,6 +71,7 @@ const listbox = [
|
||||
// }
|
||||
|
||||
const App = () => {
|
||||
const ref = useRef()
|
||||
const [selectedItem, setSelectedItem] = useState(undef)
|
||||
|
||||
const onSelect = useCallback(
|
||||
@@ -98,6 +99,7 @@ const App = () => {
|
||||
<div>
|
||||
<label htmlFor="autocomplete">Search:</label>
|
||||
<Turnstone
|
||||
ref={ref}
|
||||
autoFocus={false}
|
||||
cancelButton={true}
|
||||
clearButton={true}
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "turnstone",
|
||||
"version": "1.2.3",
|
||||
"version": "1.3.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "turnstone",
|
||||
"version": "1.2.3",
|
||||
"version": "1.3.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
@@ -16,7 +16,7 @@
|
||||
"setify": "^1.0.4",
|
||||
"split-match": "^0.2.2",
|
||||
"swr": "^1.1.2",
|
||||
"turnstone-recent-searches": "^0.4.0",
|
||||
"turnstone-recent-searches": "^0.5.0",
|
||||
"use-debounce": "^7.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -5008,9 +5008,9 @@
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/turnstone-recent-searches": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/turnstone-recent-searches/-/turnstone-recent-searches-0.4.0.tgz",
|
||||
"integrity": "sha512-3/ejeRHv+awlU2mI6l3dFXmbvzCsi0KgEmbJ7AD/X50d0Eu7VbJXnoH5RsMU4rFuO6swPGMhsuTx5Dl48MyBLw=="
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/turnstone-recent-searches/-/turnstone-recent-searches-0.5.0.tgz",
|
||||
"integrity": "sha512-OFGRM92OKAx467QTYeJXJY5Uj1XhPiMmqiXwL1/wPky38SLXotyxVjFpMvCb8MuGsY61fsJDkF2vsmseae42VA=="
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
@@ -9061,9 +9061,9 @@
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"turnstone-recent-searches": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/turnstone-recent-searches/-/turnstone-recent-searches-0.4.0.tgz",
|
||||
"integrity": "sha512-3/ejeRHv+awlU2mI6l3dFXmbvzCsi0KgEmbJ7AD/X50d0Eu7VbJXnoH5RsMU4rFuO6swPGMhsuTx5Dl48MyBLw=="
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/turnstone-recent-searches/-/turnstone-recent-searches-0.5.0.tgz",
|
||||
"integrity": "sha512-OFGRM92OKAx467QTYeJXJY5Uj1XhPiMmqiXwL1/wPky38SLXotyxVjFpMvCb8MuGsY61fsJDkF2vsmseae42VA=="
|
||||
},
|
||||
"type-check": {
|
||||
"version": "0.4.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "turnstone",
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.0",
|
||||
"description": "React customisable autocomplete component with typeahead and grouped results from multiple APIs.",
|
||||
"author": "Tom Southall",
|
||||
"keywords": [
|
||||
@@ -52,7 +52,7 @@
|
||||
"setify": "^1.0.4",
|
||||
"split-match": "^0.2.2",
|
||||
"swr": "^1.1.2",
|
||||
"turnstone-recent-searches": "^0.4.0",
|
||||
"turnstone-recent-searches": "^0.5.0",
|
||||
"use-debounce": "^7.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useRef, useContext } from 'react'
|
||||
import React, { useState, useRef, useContext, useImperativeHandle } from 'react'
|
||||
import { StateContext } from '../context/state'
|
||||
import Listbox from './listbox'
|
||||
import Errorbox from './errorbox'
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
clear
|
||||
} from '../actions/actions'
|
||||
|
||||
export default function Container(props) {
|
||||
const Container = React.forwardRef((props, ref) => {
|
||||
// Destructure props
|
||||
const {
|
||||
autoFocus,
|
||||
@@ -202,6 +202,29 @@ export default function Container(props) {
|
||||
setBlockBlurHandler(false)
|
||||
}
|
||||
|
||||
// Expose methods to parent components
|
||||
useImperativeHandle(ref, () => ({
|
||||
focus: () => {
|
||||
queryInput.current.focus()
|
||||
},
|
||||
blur: () => {
|
||||
queryInput.current.blur()
|
||||
},
|
||||
select: () => {
|
||||
queryInput.current.select()
|
||||
},
|
||||
clear: () => {
|
||||
clearState()
|
||||
},
|
||||
query: (query) => {
|
||||
if(typeof query === 'string') {
|
||||
queryInput.current.value = query
|
||||
queryInput.current.focus()
|
||||
handleInput()
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div
|
||||
@@ -288,4 +311,8 @@ export default function Container(props) {
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
Container.displayName = 'Container'
|
||||
|
||||
export default Container
|
||||
|
||||
@@ -28,12 +28,12 @@ const propDefaults = {
|
||||
Clear: () => '\u00d7'
|
||||
}
|
||||
|
||||
const render = (Component, componentProps, pluginIndex) => {
|
||||
const render = (Component, componentProps, pluginIndex, ref) => {
|
||||
const p = Array.isArray(componentProps.plugins) && componentProps.plugins[pluginIndex]
|
||||
if(p) {
|
||||
const [Plugin, pluginProps] = Array.isArray(p) ? p : [p]
|
||||
|
||||
return <Plugin {...{
|
||||
return <Plugin ref={ref} {...{
|
||||
...pluginProps,
|
||||
Component,
|
||||
componentProps,
|
||||
@@ -41,20 +41,24 @@ const render = (Component, componentProps, pluginIndex) => {
|
||||
render
|
||||
}} />
|
||||
}
|
||||
return <Component {...componentProps} />
|
||||
return <Component ref={ref} {...componentProps} />
|
||||
}
|
||||
|
||||
export default function Turnstone(props) {
|
||||
const Turnstone = React.forwardRef((props, ref) => {
|
||||
const componentProps = {...propDefaults, ...props}
|
||||
|
||||
return (
|
||||
<React.StrictMode>
|
||||
<StateContextProvider {...componentProps}>
|
||||
{ render(Container, componentProps, 0) }
|
||||
{ render(Container, componentProps, 0, ref) }
|
||||
</StateContextProvider>
|
||||
</React.StrictMode>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
Turnstone.displayName = 'Turnstone'
|
||||
|
||||
export default Turnstone
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Prop validation //
|
||||
|
||||
Reference in New Issue
Block a user