Add type definitions for @webscopeio/react-textarea-autocomplete (#27535)

* Add types for @webscopeio/react-textarea-autocomplete

* Fixes for lint
This commit is contained in:
Michal Zochowski
2018-07-24 18:04:51 +02:00
committed by Andy
parent 478ef05b4f
commit e037e4212e
4 changed files with 292 additions and 0 deletions

View File

@@ -0,0 +1,191 @@
// Type definitions for webscopeio__react-textarea-autocomplete 2.3
// Project: https://github.com/webscopeio/react-textarea-autocomplete
// Definitions by: Michal Zochowski <https://github.com/michauzo>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.9
export default ReactTextareaAutocomplete;
export as namespace ReactTextareaAutocomplete;
import * as React from "react";
export type CaretPositionType = 'start' | 'end' | 'next' | number;
export interface TextToReplaceType {
text: string;
caretPosition: CaretPositionType;
key?: string;
}
export type DataProviderType<TItem> = (token: string) =>
| Promise<TItem[]>
| TItem[];
export interface ItemComponentProps<TItem> {
selected: boolean;
entity: TItem;
}
/**
* Textarea Types
*/
export interface SettingType<TItem> {
/**
* The component for rendering the item in suggestion list. It has selected and entity props provided by React Textarea Autocomplete.
*/
component: React.SFC<ItemComponentProps<TItem>>;
/**
* Called after each keystroke to get data what the suggestion list should display (array or promise resolving array).
*/
dataProvider: DataProviderType<TItem>;
/**
* Set this to true if you want to provide autocomplete for words (tokens) containing whitespace.
* @default false
*/
allowWhitespace?: boolean;
/**
* Show autocomplete only if it's preceded by whitespace. Cannot be combined with allowWhitespace.
* @default false
*/
afterWhitespace?: boolean;
/**
* (Optional for string based item. If the item is an object this method is required) This function defines text
* which will be placed into textarea after the user makes a selection.
*
* You can also specify the behavior of caret if you return object {text: "item", caretPosition: "start"} the caret
* will be before the word once the user confirms his selection. Other possible value are "next", "end" and number,
* which is absolute number in contex of textarea (0 is equal position before the first char). Defaults to "next"
* which is space after the injected word.
*
* The default behavior for string based item is a string: <TRIGGER><ITEM><TRIGGER>). This method should always
* return a unique string, otherwise, you have to use object notation and specify your own key or return object
* from dataProvider with key property.
*/
output?: (item: TItem, trigger?: string) => TextToReplaceType | string;
}
export interface TriggerType<TItem> {
[key: string]: SettingType<TItem>;
}
type PickedAttributes = "onChange" | "onSelect" | "onBlur" | "value";
export interface TextareaProps<TItem> extends Pick<React.InputHTMLAttributes<HTMLTextAreaElement>, PickedAttributes> {
/**
* Define triggers and their corresponding behavior.
*/
trigger: TriggerType<TItem>;
/**
* Gets data props which is already fetched (and displayed) suggestion.
*/
loadingComponent: React.SFC;
/**
* Listener called every time the textarea's caret position is changed. The listener is called with one attribute - caret position denoted by an integer number.
*/
onCaretPositionChange?: (pos: number) => void;
/**
* Allows you to get React ref of the underlying textarea.
*/
innerRef?: (ref: HTMLTextAreaElement) => void;
/**
* With default implementation it will scroll the dropdown every time when the item gets out of the view.
* @default true
*/
scrollToItem?: boolean | ((container: HTMLDivElement, item: HTMLDivElement) => void);
/**
* When it's true autocomplete will close when use click outside.
* @default false
*/
closeOnClickOutside?: boolean;
/**
* When it's true the textarea will move along with a caret as a user continues to type.
* @default false
*/
movePopupAsYouType?: boolean;
/**
* Number of characters that user should type for trigger a suggestion.
* @default 1
*/
minChar?: number;
/**
* Styles of textarea
*/
style?: React.CSSProperties;
/**
* Styles of list's wrapper.
*/
listStyle?: React.CSSProperties;
/**
* Styles of item's wrapper.
*/
itemStyle?: React.CSSProperties;
/**
* Styles of textarea's container.
*/
containerStyle?: React.CSSProperties;
/**
* Styles of loader's wrapper.
*/
loaderStyle?: React.CSSProperties;
/**
* Styles of dropdown's wrapper.
*/
dropdownStyle?: React.CSSProperties;
/**
* ClassNames of the textarea.
*/
className?: string;
/**
* ClassNames of the textarea's container.
*/
containerClassName?: string;
/**
* ClassNames of list's wrapper.
*/
listClassName?: string;
/**
* ClassNames of item's wrapper.
*/
itemClassName?: string;
/**
* ClassNames of loader's wrapper.
*/
loaderClassName?: string;
/**
* ClassNames of dropdown's wrapper.
*/
dropdownClassName?: string;
}
export interface TextareaState<TItem> {
currentTrigger?: string;
top?: number;
left?: number;
actualToken: string;
data?: TItem[];
value: string;
dataLoading: boolean;
selectionEnd: number;
selectionStart: number;
component?: React.SFC<ItemComponentProps<TItem>>;
}
declare class ReactTextareaAutocomplete<TItem extends string | object> extends React.Component<TextareaProps<TItem>, TextareaState<TItem>> {
/**
* Gets the current caret position in the textarea.
*/
getCaretPosition(): number;
/**
* Sets the caret position to the integer value passed as the argument.
* @param position caret position to set.
*/
setCaretPosition(position: number): void;
/**
* Returns selectionStart and selectionEnd of the textarea.
*/
getSelectionPosition(): { selectionStart: number, selectionEnd: number };
/**
* Returns currently selected word.
*/
getSelectedText(): string | undefined;
}

View File

@@ -0,0 +1,28 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"jsx": "react",
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"paths": {
"@webscopeio/react-textarea-autocomplete": ["webscopeio__react-textarea-autocomplete"]
}
},
"files": [
"index.d.ts",
"webscopeio__react-textarea-autocomplete-tests.tsx"
]
}

View File

@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }

View File

@@ -0,0 +1,72 @@
import ReactTextareaAutocomplete from "webscopeio__react-textarea-autocomplete";
import * as React from "react";
const Loading: React.SFC = () => {
return <div>Loading</div>;
};
interface ItemProps {
selected: boolean;
entity: string;
}
const Item: React.SFC<ItemProps> = (props: ItemProps) => {
return <div className={`item${props.selected ? " selected" : ""}`}>props</div>;
};
class Autocomplete extends React.Component {
private rta: ReactTextareaAutocomplete<string> | null;
private textarea: HTMLTextAreaElement;
private readonly names = [ "abc", "def", "ghi" ];
render() {
return <ReactTextareaAutocomplete<string>
className="my-textarea"
loadingComponent={Loading}
style={{
fontSize: "18px",
lineHeight: "20px",
padding: 5
}}
ref={(rta) => { this.rta = rta; }}
innerRef={(textarea) => { this.textarea = textarea; }}
containerStyle={{
marginTop: 20,
width: 400,
height: 100,
margin: "20px auto"
}}
minChar={0}
trigger={{
":": {
dataProvider: token => {
return this.names
.filter((name) => name.startsWith(token));
},
component: Item,
output: (item, token) => item,
allowWhitespace: true,
afterWhitespace: false
}
}}
value="aaa"
closeOnClickOutside={false}
movePopupAsYouType={false}
onBlur={(evt: React.FocusEvent<HTMLTextAreaElement>) => { console.log(evt); }}
onSelect={(evt: React.SyntheticEvent<HTMLTextAreaElement>) => { console.log(evt); }}
onChange={(evt: React.ChangeEvent<HTMLTextAreaElement>) => { console.log(evt); }}
scrollToItem={false}
onCaretPositionChange={(pos: number) => { console.log(pos); }}
containerClassName="container"
dropdownClassName="dropdown"
itemClassName="item"
listClassName="list"
loaderClassName="loader"
dropdownStyle={{ width: "100%", margin: "14px"}}
itemStyle={{ width: "100%", margin: "14px"}}
listStyle={{ width: "100%", margin: "14px"}}
loaderStyle={{ width: "100%", margin: "14px"}}
/>;
}
}