Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert EuiFieldSearch to TS #2775

Merged
merged 3 commits into from
Jan 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
## [`master`](https://github.com/elastic/eui/tree/master)

- Converted `EuiFormRow` to Typescript ([#2712](https://github.com/elastic/eui/pull/2712))
- Converted `EuiFormRow` to TypeScript ([#2712](https://github.com/elastic/eui/pull/2712))
- Updated `logoAPM`, `logoSecurity` and `logoEnterpriseSearch`. Added `logoWorkplaceSearch` and `logoObservability` ([#2769](https://github.com/elastic/eui/pull/2769))
- Convert `EuiFilterButton` to TypeScript ([#2761](https://github.com/elastic/eui/pull/2761))
- Convert `EuiFilterSelectItem` to TypeScript ([#2761](https://github.com/elastic/eui/pull/2761))
- Converted `EuiFilterButton` to TypeScript ([#2761](https://github.com/elastic/eui/pull/2761))
- Converted `EuiFilterSelectItem` to TypeScript ([#2761](https://github.com/elastic/eui/pull/2761))
- Converted `EuiFieldSearch` to TypeScript ([#2775](https://github.com/elastic/eui/pull/2775))

**Bug fixes**

Expand Down
Original file line number Diff line number Diff line change
@@ -1,70 +1,70 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import React, { Component, InputHTMLAttributes } from 'react';
import classNames from 'classnames';
import { Browser } from '../../../services/browser';
import { ENTER } from '../../../services/key_codes';
import { CommonProps } from '../../common';

import { EuiFormControlLayout } from '../form_control_layout';

import { EuiValidatableControl } from '../validatable_control';

const propTypes = {
name: PropTypes.string,
id: PropTypes.string,
placeholder: PropTypes.string,
value: PropTypes.string,
isInvalid: PropTypes.bool,
fullWidth: PropTypes.bool,
isLoading: PropTypes.bool,
inputRef: PropTypes.func,
export interface EuiFieldSearchProps
extends CommonProps,
InputHTMLAttributes<HTMLInputElement> {
name?: string;
id?: string;
placeholder?: string;
value?: string;
isInvalid?: boolean;
fullWidth?: boolean;
isLoading?: boolean;
/**
* Called when the user presses [Enter] OR on change if the incremental prop is `true`.
* If you don't need the on[Enter] functionality, prefer using onChange
*/
onSearch: PropTypes.func,
onSearch?: (value: string) => void;
/**
* When `true` the search will be executed (that is, the `onSearch` will be called) as the
* user types.
*/
incremental: PropTypes.bool,
incremental?: boolean;
/**
* when `true` creates a shorter height input
*/
compressed: PropTypes.bool,
compressed?: boolean;
inputRef?: (node: HTMLInputElement | null) => void;
/**
* Shows a button that quickly clears any input
*/
isClearable: PropTypes.bool,
};

const defaultProps = {
fullWidth: false,
isLoading: false,
incremental: false,
compressed: false,
isClearable: true,
};

export class EuiFieldSearch extends Component {
static propTypes = propTypes;
static defaultProps = defaultProps;

constructor(props) {
super(props);
this.cleanups = [];
}
isClearable?: boolean;
}

export class EuiFieldSearch extends Component<EuiFieldSearchProps> {
static defaultProps = {
fullWidth: false,
isLoading: false,
incremental: false,
compressed: false,
isClearable: true,
};

inputElement: HTMLInputElement | null = null;
cleanups: Array<() => void> = [];

componentDidMount() {
if (!this.inputElement) return;
if (Browser.isEventSupported('search', this.inputElement)) {
const onSearch = event => {
const onSearch = (event?: Event) => {
if (this.props.onSearch) {
this.props.onSearch(event.target.value);
if (!event || !event.target) return;
this.props.onSearch((event.target as HTMLInputElement).value);
}
};
this.inputElement.addEventListener('search', onSearch);
this.cleanups.push(() =>
this.inputElement.removeEventListener('search', onSearch)
);
this.cleanups.push(() => {
if (!this.inputElement) return;
this.inputElement.removeEventListener('search', onSearch);
});
}
}

Expand All @@ -79,50 +79,63 @@ export class EuiFieldSearch extends Component {
// only then will React treat the value as different and fire its `change` event
//
// https://stackoverflow.com/questions/23892547/what-is-the-best-way-to-trigger-onchange-event-in-react-js
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
const nativeInputValue = Object.getOwnPropertyDescriptor(
HTMLInputElement.prototype,
'value'
).set;
nativeInputValueSetter.call(this.inputElement, '');
);
const nativeInputValueSetter = nativeInputValue
? nativeInputValue.set
: undefined;
if (nativeInputValueSetter) {
nativeInputValueSetter.call(this.inputElement, '');
}

// dispatch input event, with IE11 support/fallback
let event;
if ('Event' in window && typeof Event === 'function') {
const event = new Event('input', {
event = new Event('input', {
bubbles: true,
cancelable: false,
});
this.inputElement.dispatchEvent(event);
} else {
// IE11
const event = document.createEvent('Event');
event = document.createEvent('Event');
event.initEvent('input', true, false);
this.inputElement.dispatchEvent(event);
}

// set focus on the search field
this.inputElement.focus();
if (this.inputElement) {
if (event) {
this.inputElement.dispatchEvent(event);
}
// set focus on the search field
this.inputElement.focus();
}
};

componentWillUnmount() {
this.cleanups.forEach(cleanup => cleanup());
}

setRef = inputElement => {
setRef = (inputElement: HTMLInputElement | null) => {
this.inputElement = inputElement;
if (this.props.inputRef) {
this.props.inputRef(inputElement);
}
};

onKeyUp = (incremental, onSearch, event) => {
onKeyUp = (
event: React.KeyboardEvent<HTMLInputElement>,
incremental?: boolean,
onSearch?: (value: string) => void
) => {
if (this.props.onKeyUp) {
this.props.onKeyUp(event);
if (event.defaultPrevented) {
return;
}
}
if (onSearch && (incremental || event.keyCode === ENTER)) {
onSearch(event.target.value);
onSearch((event.target as HTMLInputElement).value);
}
};

Expand Down Expand Up @@ -162,7 +175,7 @@ export class EuiFieldSearch extends Component {
clear={
isClearable && value && !rest.readOnly && !rest.disabled
? { onClick: this.onClear }
: null
: undefined
}
compressed={compressed}>
<EuiValidatableControl isInvalid={isInvalid}>
Expand All @@ -173,7 +186,7 @@ export class EuiFieldSearch extends Component {
placeholder={placeholder}
className={classes}
value={value}
onKeyUp={this.onKeyUp.bind(this, incremental, onSearch)}
onKeyUp={e => this.onKeyUp(e, incremental, onSearch)}
ref={this.setRef}
{...rest}
/>
Expand Down
29 changes: 0 additions & 29 deletions src/components/form/field_search/index.d.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/components/form/field_search/index.js

This file was deleted.

1 change: 1 addition & 0 deletions src/components/form/field_search/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { EuiFieldSearch, EuiFieldSearchProps } from './field_search';
3 changes: 0 additions & 3 deletions src/components/form/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { CommonProps } from '../common';
/// <reference path="./field_search/index.d.ts" />
/// <reference path="./range/index.d.ts" />
/// <reference path="./select/index.d.ts" />
/// <reference path="./super_select/index.d.ts" />

import { FunctionComponent, FormHTMLAttributes, ReactNode } from 'react';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import React, { Component, InputHTMLAttributes } from 'react';
import classNames from 'classnames';
import { CommonProps } from '../../common';
// @ts-ignore
import { EuiFieldSearch } from '../../form/field_search';
import { EuiFieldSearch, EuiFieldSearchProps } from '../../form/field_search';
import { getMatchingOptions } from '../matching_options';
import { Option } from '../types';

/// <reference path="../../form/field_search/index.d.ts" />
import { EuiFieldSearchProps } from '@elastic/eui'; // eslint-disable-line

export type EuiSelectableSearchProps = Omit<
InputHTMLAttributes<HTMLInputElement> & EuiFieldSearchProps,
'onChange'
Expand Down