mirror of
https://github.com/zhigang1992/DefinitelyTyped.git
synced 2026-06-05 06:40:35 +08:00
Merge pull request #21836 from rosskevin/react-autosuggest-updates
[react-autosuggest] update signatures, documentation, use generic type
This commit is contained in:
28
types/react-autosuggest/README.md
Normal file
28
types/react-autosuggest/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# react-autosuggest usage notes
|
||||
|
||||
The definition uses generics for stronger typing. Read the [TypeScript deep dive on JSX Generic components](https://basarat.gitbooks.io/typescript/docs/jsx/tsx.html#react-jsx-tip-generic-components) for details on consuming these type definitions.
|
||||
|
||||
## Example
|
||||
|
||||
```jsx
|
||||
import * as Autosuggest from 'react-autosuggest'
|
||||
interface Language {
|
||||
name: string
|
||||
year: number
|
||||
}
|
||||
|
||||
const LanguageAutosuggest = Autosuggest as { new (): Autosuggest<Language> }
|
||||
|
||||
<LanguageAutosuggest
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested.bind(this)}
|
||||
getSuggestionValue={this.getSuggestionValue}
|
||||
renderSuggestion={this.renderSuggestion}
|
||||
onSuggestionSelected={this.onSuggestionsSelected}
|
||||
alwaysRenderSuggestions={true}
|
||||
inputProps={inputProps}
|
||||
theme={theme}
|
||||
/>
|
||||
```
|
||||
|
||||
Find multiple full examples in `react-autosuggest-tests.tsx`
|
||||
238
types/react-autosuggest/index.d.ts
vendored
238
types/react-autosuggest/index.d.ts
vendored
@@ -5,84 +5,200 @@
|
||||
// Robert Essig <https://github.com/robessog>
|
||||
// Terry Bayne <https://github.com/tbayne>
|
||||
// Christopher Deutsch <https://github.com/cdeutsch>
|
||||
// Kevin Ross <https://github.com/rosskevin>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 2.3
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
declare class Autosuggest extends React.Component<Autosuggest.AutosuggestProps> {}
|
||||
declare class Autosuggest<T = any> extends React.Component<Autosuggest.AutosuggestProps<T>> {}
|
||||
|
||||
export = Autosuggest;
|
||||
|
||||
declare namespace Autosuggest {
|
||||
interface SuggestionsFetchRequest {
|
||||
value: string;
|
||||
reason: 'input-changed' | 'input-focused' | 'escape-pressed' | 'suggestions-revealed' | 'suggestion-selected';
|
||||
}
|
||||
/**
|
||||
* Utilies types based on:
|
||||
* https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-307871458
|
||||
*/
|
||||
|
||||
interface InputValues {
|
||||
value: string;
|
||||
valueBeforeUpDown?: string;
|
||||
}
|
||||
/** @internal */
|
||||
type Diff<T extends string, U extends string> = ({ [P in T]: P } &
|
||||
{ [P in U]: never } & { [x: string]: never })[T];
|
||||
|
||||
interface RenderSuggestionParams {
|
||||
query: string;
|
||||
isHighlighted: boolean;
|
||||
}
|
||||
/** @internal */
|
||||
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;
|
||||
|
||||
interface SuggestionHighlightedParams {
|
||||
suggestion: any;
|
||||
}
|
||||
interface SuggestionsFetchRequestedParams {
|
||||
value: string;
|
||||
reason:
|
||||
| 'input-changed'
|
||||
| 'input-focused'
|
||||
| 'escape-pressed'
|
||||
| 'suggestions-revealed'
|
||||
| 'suggestion-selected';
|
||||
}
|
||||
|
||||
interface ChangeEvent {
|
||||
newValue: string;
|
||||
method: 'down' | 'up' | 'escape' | 'enter' | 'click' | 'type';
|
||||
}
|
||||
interface RenderSuggestionParams {
|
||||
query: string;
|
||||
isHighlighted: boolean;
|
||||
}
|
||||
|
||||
interface BlurEvent {
|
||||
highlightedSuggestion: any;
|
||||
}
|
||||
interface SuggestionHighlightedParams {
|
||||
suggestion: any;
|
||||
}
|
||||
|
||||
interface InputProps extends React.InputHTMLAttributes<any> {
|
||||
value: string;
|
||||
onChange(event: React.FormEvent<any>, params?: ChangeEvent): void;
|
||||
onBlur?(event: React.FormEvent<any>, params?: BlurEvent): void;
|
||||
[key: string]: any;
|
||||
}
|
||||
interface ChangeEvent {
|
||||
newValue: string;
|
||||
method: 'down' | 'up' | 'escape' | 'enter' | 'click' | 'type';
|
||||
}
|
||||
|
||||
interface SuggestionSelectedEventData<TSuggestion> {
|
||||
suggestion: TSuggestion;
|
||||
suggestionValue: string;
|
||||
suggestionIndex: number;
|
||||
sectionIndex: number | null;
|
||||
method: 'click' | 'enter';
|
||||
}
|
||||
interface BlurEvent<TSuggestion> {
|
||||
highlightedSuggestion: TSuggestion;
|
||||
}
|
||||
|
||||
type ThemeKey = 'container' | 'containerOpen' | 'input' | 'inputOpen' | 'inputFocused' | 'suggestionsContainer' |
|
||||
'suggestionsContainerOpen' | 'suggestionsList' | 'suggestion' | 'suggestionFirst' | 'suggestionHighlighted' |
|
||||
'sectionContainer' | 'sectionContainerFirst' | 'sectionTitle';
|
||||
interface InputProps<TSuggestion>
|
||||
extends Omit<React.InputHTMLAttributes<any>, 'onChange' | 'onBlur'> {
|
||||
onChange(event: React.FormEvent<any>, params?: ChangeEvent): void;
|
||||
onBlur?(event: React.FormEvent<any>, params?: BlurEvent<TSuggestion>): void;
|
||||
value: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
type Theme = Record<string, string | React.CSSProperties> | Partial<Record<ThemeKey, string | React.CSSProperties>>;
|
||||
interface SuggestionSelectedEventData<TSuggestion> {
|
||||
suggestion: TSuggestion;
|
||||
suggestionValue: string;
|
||||
suggestionIndex: number;
|
||||
sectionIndex: number | null;
|
||||
method: 'click' | 'enter';
|
||||
}
|
||||
|
||||
interface AutosuggestProps extends React.Props<Autosuggest> {
|
||||
suggestions: any[];
|
||||
onSuggestionsFetchRequested(request: SuggestionsFetchRequest): void;
|
||||
onSuggestionsClearRequested?(): void;
|
||||
getSuggestionValue(suggestion: any): any;
|
||||
renderSuggestion(suggestion: any, params: RenderSuggestionParams): JSX.Element;
|
||||
inputProps: InputProps;
|
||||
onSuggestionSelected?(event: React.FormEvent<any>, data: SuggestionSelectedEventData<any>): void;
|
||||
onSuggestionHighlighted?(params: SuggestionHighlightedParams): void;
|
||||
shouldRenderSuggestions?(value: string): boolean;
|
||||
alwaysRenderSuggestions?: boolean;
|
||||
highlightFirstSuggestion?: boolean;
|
||||
focusInputOnSuggestionClick?: boolean;
|
||||
multiSection?: boolean;
|
||||
renderSectionTitle?(section: any): JSX.Element;
|
||||
getSectionSuggestions?(section: any): any[];
|
||||
renderInputComponent?(inputProps: InputProps): JSX.Element;
|
||||
renderSuggestionsContainer?(containerProps: any, children: any, query: string): JSX.Element;
|
||||
theme?: Theme;
|
||||
id?: string;
|
||||
}
|
||||
type ThemeKey =
|
||||
| 'container'
|
||||
| 'containerOpen'
|
||||
| 'input'
|
||||
| 'inputOpen'
|
||||
| 'inputFocused'
|
||||
| 'suggestionsContainer'
|
||||
| 'suggestionsContainerOpen'
|
||||
| 'suggestionsList'
|
||||
| 'suggestion'
|
||||
| 'suggestionFirst'
|
||||
| 'suggestionHighlighted'
|
||||
| 'sectionContainer'
|
||||
| 'sectionContainerFirst'
|
||||
| 'sectionTitle';
|
||||
|
||||
type Theme =
|
||||
| Record<string, string | React.CSSProperties>
|
||||
| Partial<Record<ThemeKey, string | React.CSSProperties>>;
|
||||
|
||||
interface RenderSuggestionsContainerParams {
|
||||
containerProps: {
|
||||
id: string;
|
||||
key: string;
|
||||
ref: any;
|
||||
style: any;
|
||||
};
|
||||
children: React.ReactNode;
|
||||
query: string;
|
||||
}
|
||||
|
||||
// types for functions - allowing reuse externally - e.g. as props and bound in the constructor
|
||||
type GetSectionSuggestions<TSuggestion> = (section: any) => TSuggestion[];
|
||||
type GetSuggestionValue<TSuggestion> = (suggestion: TSuggestion) => string;
|
||||
type OnSuggestionHighlighted = (params: SuggestionHighlightedParams) => void;
|
||||
type SuggestionsFetchRequested = (request: SuggestionsFetchRequestedParams) => void;
|
||||
type OnSuggestionsClearRequested = () => void;
|
||||
type OnSuggestionSelected<TSuggestion> = (
|
||||
event: React.FormEvent<any>,
|
||||
data: SuggestionSelectedEventData<TSuggestion>,
|
||||
) => void;
|
||||
type RenderInputComponent<TSuggestion> = (inputProps: InputProps<TSuggestion>) => React.ReactNode;
|
||||
type RenderSuggestionsContainer = (params: RenderSuggestionsContainerParams) => React.ReactNode;
|
||||
type RenderSectionTitle = (section: any) => React.ReactNode;
|
||||
type RenderSuggestion<TSuggestion> = (
|
||||
suggestion: TSuggestion,
|
||||
params: RenderSuggestionParams,
|
||||
) => React.ReactNode;
|
||||
type ShouldRenderSuggestions = (value: string) => boolean;
|
||||
|
||||
interface AutosuggestProps<TSuggestion> {
|
||||
/**
|
||||
* Set it to true if you'd like to render suggestions even when the input is not focused.
|
||||
*/
|
||||
alwaysRenderSuggestions?: boolean;
|
||||
/**
|
||||
* Set it to false if you don't want Autosuggest to keep the input focused when suggestions are clicked/tapped.
|
||||
*/
|
||||
focusInputOnSuggestionClick?: boolean;
|
||||
/**
|
||||
* Implement it to teach Autosuggest where to find the suggestions for every section.
|
||||
*/
|
||||
getSectionSuggestions?: GetSectionSuggestions<TSuggestion>;
|
||||
/**
|
||||
* Implement it to teach Autosuggest what should be the input value when suggestion is clicked.
|
||||
*/
|
||||
getSuggestionValue: GetSuggestionValue<TSuggestion>;
|
||||
/**
|
||||
* Set it to true if you'd like Autosuggest to automatically highlight the first suggestion.
|
||||
*/
|
||||
highlightFirstSuggestion?: boolean;
|
||||
/**
|
||||
* Use it only if you have multiple Autosuggest components on a page.
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* Pass through arbitrary props to the input. It must contain at least value and onChange.
|
||||
*/
|
||||
inputProps: InputProps<TSuggestion>;
|
||||
/**
|
||||
* Set it to true if you'd like to display suggestions in multiple sections (with optional titles).
|
||||
*/
|
||||
multiSection?: boolean;
|
||||
/**
|
||||
* Will be called every time the highlighted suggestion changes.
|
||||
*/
|
||||
onSuggestionHighlighted?: OnSuggestionHighlighted;
|
||||
/**
|
||||
* Will be called every time you need to recalculate suggestions.
|
||||
*/
|
||||
onSuggestionsFetchRequested: SuggestionsFetchRequested;
|
||||
/**
|
||||
* Will be called every time you need to set suggestions to [].
|
||||
*/
|
||||
onSuggestionsClearRequested?: OnSuggestionsClearRequested;
|
||||
/**
|
||||
* Will be called every time suggestion is selected via mouse or keyboard.
|
||||
*/
|
||||
onSuggestionSelected?: OnSuggestionSelected<TSuggestion>;
|
||||
/**
|
||||
* Use it only if you need to customize the rendering of the input.
|
||||
*/
|
||||
renderInputComponent?: RenderInputComponent<TSuggestion>;
|
||||
/**
|
||||
* Use it if you want to customize things inside the suggestions container beyond rendering the suggestions themselves.
|
||||
*/
|
||||
renderSuggestionsContainer?: RenderSuggestionsContainer;
|
||||
/**
|
||||
* Use your imagination to define how section titles are rendered.
|
||||
*/
|
||||
renderSectionTitle?: RenderSectionTitle;
|
||||
/**
|
||||
* Use your imagination to define how suggestions are rendered.
|
||||
*/
|
||||
renderSuggestion: RenderSuggestion<TSuggestion>;
|
||||
/**
|
||||
* When the input is focused, Autosuggest will consult this function when to render suggestions.
|
||||
* Use it, for example, if you want to display suggestions when input value is at least 2 characters long.
|
||||
*/
|
||||
shouldRenderSuggestions?: ShouldRenderSuggestions;
|
||||
/**
|
||||
* These are the suggestions that will be displayed. Items can take an arbitrary shape.
|
||||
*/
|
||||
suggestions: TSuggestion[];
|
||||
/**
|
||||
* Use your imagination to style the Autosuggest.
|
||||
*/
|
||||
theme?: Theme;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,132 @@ export class ReactAutosuggestBasicTest extends React.Component<any, any> {
|
||||
};
|
||||
|
||||
return <Autosuggest
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={this
|
||||
.onSuggestionsFetchRequested
|
||||
.bind(this)}
|
||||
getSuggestionValue={this.getSuggestionValue}
|
||||
renderSuggestion={this.renderSuggestion}
|
||||
onSuggestionSelected={this.onSuggestionsSelected}
|
||||
alwaysRenderSuggestions={true}
|
||||
inputProps={inputProps}
|
||||
theme={theme}/>;
|
||||
}
|
||||
|
||||
protected onSuggestionsSelected(event: React.FormEvent<any>, data: Autosuggest.SuggestionSelectedEventData<Language>): void {
|
||||
alert(`Selected language is ${data.suggestion.name} (${data.suggestion.year}).`);
|
||||
}
|
||||
|
||||
protected renderSuggestion(suggestion: Language, params: Autosuggest.RenderSuggestionParams): JSX.Element {
|
||||
const className = params.isHighlighted ? "highlighted" : undefined;
|
||||
return <span className={className}>{suggestion.name}</span>;
|
||||
}
|
||||
// endregion region Event handlers
|
||||
protected onChange(event: React.FormEvent<any>, {newValue, method}: any): void {
|
||||
this.setState({value: newValue});
|
||||
}
|
||||
|
||||
protected onSuggestionsFetchRequested({value}: any): void {
|
||||
this.setState({
|
||||
suggestions: this.getSuggestions(value)
|
||||
});
|
||||
}
|
||||
// endregion region Helper methods
|
||||
protected getSuggestions(value: string): Language[] {
|
||||
const escapedValue = escapeRegexCharacters(value.trim());
|
||||
|
||||
if (escapedValue === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const regex = new RegExp('^' + escapedValue, 'i');
|
||||
|
||||
return ReactAutosuggestBasicTest
|
||||
.languages
|
||||
.filter(language => regex.test(language.name));
|
||||
}
|
||||
|
||||
protected getSuggestionValue(suggestion: Language): string { return suggestion.name; }
|
||||
// endregion
|
||||
}
|
||||
|
||||
const LanguageAutosuggest = Autosuggest as { new (): Autosuggest<Language> };
|
||||
|
||||
export class ReactAutosuggestTypedTest extends React.Component<any, any> {
|
||||
// region Fields
|
||||
static languages: Language[] = [
|
||||
{
|
||||
name: 'C',
|
||||
year: 1972
|
||||
}, {
|
||||
name: 'C#',
|
||||
year: 2000
|
||||
}, {
|
||||
name: 'C++',
|
||||
year: 1983
|
||||
}, {
|
||||
name: 'Clojure',
|
||||
year: 2007
|
||||
}, {
|
||||
name: 'Elm',
|
||||
year: 2012
|
||||
}, {
|
||||
name: 'Go',
|
||||
year: 2009
|
||||
}, {
|
||||
name: 'Haskell',
|
||||
year: 1990
|
||||
}, {
|
||||
name: 'Java',
|
||||
year: 1995
|
||||
}, {
|
||||
name: 'Javascript',
|
||||
year: 1995
|
||||
}, {
|
||||
name: 'Perl',
|
||||
year: 1987
|
||||
}, {
|
||||
name: 'PHP',
|
||||
year: 1995
|
||||
}, {
|
||||
name: 'Python',
|
||||
year: 1991
|
||||
}, {
|
||||
name: 'Ruby',
|
||||
year: 1995
|
||||
}, {
|
||||
name: 'Scala',
|
||||
year: 2003
|
||||
}
|
||||
];
|
||||
// endregion region Constructor
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: '',
|
||||
suggestions: this.getSuggestions('')
|
||||
};
|
||||
}
|
||||
// endregion region Rendering methods
|
||||
render(): JSX.Element {
|
||||
const {value, suggestions} = this.state;
|
||||
const inputProps = {
|
||||
placeholder: `Type 'c'`,
|
||||
value,
|
||||
onChange: this
|
||||
.onChange
|
||||
.bind(this)
|
||||
};
|
||||
|
||||
const theme = {
|
||||
input: 'themed-input-class',
|
||||
container: 'themed-container-class',
|
||||
suggestionFocused: 'active',
|
||||
sectionTitle: { color: 'blue' }
|
||||
};
|
||||
|
||||
return <LanguageAutosuggest
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={this
|
||||
.onSuggestionsFetchRequested
|
||||
@@ -240,7 +366,7 @@ export class ReactAutosuggestMultipleTest extends React.Component<any, any> {
|
||||
.bind(this)
|
||||
};
|
||||
|
||||
return <Autosuggest
|
||||
return <LanguageAutosuggest
|
||||
multiSection={true}
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={this
|
||||
@@ -272,7 +398,7 @@ export class ReactAutosuggestMultipleTest extends React.Component<any, any> {
|
||||
return <strong>{section.title}</strong>;
|
||||
}
|
||||
|
||||
protected renderInputComponent(inputProps: Autosuggest.InputProps): JSX.Element {
|
||||
protected renderInputComponent(inputProps: Autosuggest.InputProps<Language>): JSX.Element {
|
||||
return (
|
||||
<div>
|
||||
<input {...inputProps} />
|
||||
@@ -280,7 +406,7 @@ export class ReactAutosuggestMultipleTest extends React.Component<any, any> {
|
||||
);
|
||||
}
|
||||
|
||||
protected renderSuggestionsContainer(containerProps: any, children: any, query: string): JSX.Element {
|
||||
protected renderSuggestionsContainer({containerProps, children, query}: Autosuggest.RenderSuggestionsContainerParams): JSX.Element {
|
||||
return (
|
||||
<div {...containerProps}>
|
||||
<span>{children}</span>
|
||||
@@ -345,6 +471,8 @@ interface Person {
|
||||
twitter: string;
|
||||
}
|
||||
|
||||
const PersonAutosuggest = Autosuggest as { new (): Autosuggest<Person> };
|
||||
|
||||
export class ReactAutosuggestCustomTest extends React.Component<any, any> {
|
||||
// region Fields
|
||||
static people: Person[] = [
|
||||
@@ -386,7 +514,7 @@ export class ReactAutosuggestCustomTest extends React.Component<any, any> {
|
||||
.bind(this)
|
||||
};
|
||||
|
||||
return<Autosuggest
|
||||
return<PersonAutosuggest
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||
getSuggestionValue={this.getSuggestionValue}
|
||||
|
||||
Reference in New Issue
Block a user