From 57d857d5f52e31aabca0cdb0d5c03962f60c3964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20Franco=20Knob?= Date: Wed, 18 Dec 2019 12:44:53 -0300 Subject: [PATCH 1/4] Converts EuiSuggest to Typescript --- CHANGELOG.md | 1 + ...est.test.js.snap => suggest.test.tsx.snap} | 0 ...st.js.snap => suggest_input.test.tsx.snap} | 0 ...est.js.snap => suggest_item.test.tsx.snap} | 0 src/components/suggest/{index.js => index.ts} | 0 src/components/suggest/suggest.js | 81 ---------- .../{suggest.test.js => suggest.test.tsx} | 0 src/components/suggest/suggest.tsx | 81 ++++++++++ src/components/suggest/suggest_input.js | 134 ---------------- ...t_input.test.js => suggest_input.test.tsx} | 0 src/components/suggest/suggest_input.tsx | 143 ++++++++++++++++++ ...est_item.test.js => suggest_item.test.tsx} | 0 .../{suggest_item.js => suggest_item.tsx} | 122 +++++++++------ 13 files changed, 300 insertions(+), 262 deletions(-) rename src/components/suggest/__snapshots__/{suggest.test.js.snap => suggest.test.tsx.snap} (100%) rename src/components/suggest/__snapshots__/{suggest_input.test.js.snap => suggest_input.test.tsx.snap} (100%) rename src/components/suggest/__snapshots__/{suggest_item.test.js.snap => suggest_item.test.tsx.snap} (100%) rename src/components/suggest/{index.js => index.ts} (100%) delete mode 100644 src/components/suggest/suggest.js rename src/components/suggest/{suggest.test.js => suggest.test.tsx} (100%) create mode 100644 src/components/suggest/suggest.tsx delete mode 100644 src/components/suggest/suggest_input.js rename src/components/suggest/{suggest_input.test.js => suggest_input.test.tsx} (100%) create mode 100644 src/components/suggest/suggest_input.tsx rename src/components/suggest/{suggest_item.test.js => suggest_item.test.tsx} (100%) rename src/components/suggest/{suggest_item.js => suggest_item.tsx} (57%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9371f3bae2c..80ff5b56735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## [`master`](https://github.com/elastic/eui/tree/master) - Converted `EuiHighlight` to Typescript ([#2681](https://github.com/elastic/eui/pull/2681)) +- Converted `EuiSuggest` to Typescript ([#](https://github.com/elastic/eui/pull/)) **Bug fixes** diff --git a/src/components/suggest/__snapshots__/suggest.test.js.snap b/src/components/suggest/__snapshots__/suggest.test.tsx.snap similarity index 100% rename from src/components/suggest/__snapshots__/suggest.test.js.snap rename to src/components/suggest/__snapshots__/suggest.test.tsx.snap diff --git a/src/components/suggest/__snapshots__/suggest_input.test.js.snap b/src/components/suggest/__snapshots__/suggest_input.test.tsx.snap similarity index 100% rename from src/components/suggest/__snapshots__/suggest_input.test.js.snap rename to src/components/suggest/__snapshots__/suggest_input.test.tsx.snap diff --git a/src/components/suggest/__snapshots__/suggest_item.test.js.snap b/src/components/suggest/__snapshots__/suggest_item.test.tsx.snap similarity index 100% rename from src/components/suggest/__snapshots__/suggest_item.test.js.snap rename to src/components/suggest/__snapshots__/suggest_item.test.tsx.snap diff --git a/src/components/suggest/index.js b/src/components/suggest/index.ts similarity index 100% rename from src/components/suggest/index.js rename to src/components/suggest/index.ts diff --git a/src/components/suggest/suggest.js b/src/components/suggest/suggest.js deleted file mode 100644 index 0f657f08c6a..00000000000 --- a/src/components/suggest/suggest.js +++ /dev/null @@ -1,81 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { EuiSuggestItem } from './suggest_item'; -import { EuiSuggestInput } from './suggest_input'; - -export class EuiSuggest extends Component { - state = { - value: '', - status: 'unsaved', - }; - - getValue = val => { - this.setState({ - value: val, - }); - }; - - onChange = e => { - this.props.onInputChange(e.target.value); - }; - - render() { - const { - onItemClick, - onInputChange, - status, - append, - tooltipContent, - suggestions, - ...rest - } = this.props; - - const suggestionList = suggestions.map((item, index) => ( - onItemClick(item) : null} - description={item.description} - /> - )); - - const suggestInput = ( - - ); - return
{suggestInput}
; - } -} - -EuiSuggest.propTypes = { - className: PropTypes.string, - /** - * Status of the current query 'notYetSaved', 'saved', 'unchanged' or 'loading'. - */ - status: PropTypes.oneOf(['unsaved', 'saved', 'unchanged', 'loading']), - tooltipContent: PropTypes.string, - /** - * Element to be appended to the input bar (e.g. hashtag popover). - */ - append: PropTypes.node, - /** - * List of suggestions to display using 'suggestItem'. - */ - suggestions: PropTypes.array, - /** - * Handler for click on a suggestItem. - */ - onItemClick: PropTypes.func, - onInputChange: PropTypes.func, -}; - -EuiSuggestInput.defaultProps = { - status: 'unchanged', -}; diff --git a/src/components/suggest/suggest.test.js b/src/components/suggest/suggest.test.tsx similarity index 100% rename from src/components/suggest/suggest.test.js rename to src/components/suggest/suggest.test.tsx diff --git a/src/components/suggest/suggest.tsx b/src/components/suggest/suggest.tsx new file mode 100644 index 00000000000..97163b6a3b1 --- /dev/null +++ b/src/components/suggest/suggest.tsx @@ -0,0 +1,81 @@ +import React, { useState, FunctionComponent } from 'react'; +import { CommonProps } from '../common'; +import { EuiSuggestItem, EuiSuggestItemProps } from './suggest_item'; +import { EuiSuggestInput } from './suggest_input'; + +export type EuiSuggestProps = CommonProps & { + tooltipContent?: string; + + /** + * Status of the current query 'notYetSaved', 'saved', 'unchanged' or 'loading'. + */ + status?: 'unsaved' | 'saved' | 'unchanged' | 'loading'; + + /** + * Element to be appended to the input bar (e.g. hashtag popover). + */ + append?: JSX.Element; + + /** + * List of suggestions to display using 'suggestItem'. + */ + suggestions: EuiSuggestItemProps[]; + + /** + * Handler for click on a suggestItem. + */ + onItemClick?: Function; + + onInputChange?: Function; +}; + +export const EuiSuggest: FunctionComponent = ( + props: EuiSuggestProps +) => { + const setValue = useState('')[1]; + + const { + onItemClick, + onInputChange, + status, + append, + tooltipContent, + suggestions, + ...rest + } = props; + + const getValue = (val: string) => { + setValue(val); + }; + + const onChange = (e: React.FormEvent) => { + onInputChange ? onInputChange(e.target) : null; + }; + + const suggestionList = suggestions.map((item: EuiSuggestItemProps, index) => ( + onItemClick(item) : undefined} + description={item.description} + /> + )); + + const suggestInput = ( + + ); + + return
{suggestInput}
; +}; + +EuiSuggestInput.defaultProps = { + status: 'unchanged', +}; diff --git a/src/components/suggest/suggest_input.js b/src/components/suggest/suggest_input.js deleted file mode 100644 index 3fc461baaa3..00000000000 --- a/src/components/suggest/suggest_input.js +++ /dev/null @@ -1,134 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { EuiFilterButton } from '../filter_group'; -import { EuiFieldText } from '../form'; -import { EuiToolTip } from '../tool_tip'; -import { EuiIcon } from '../icon'; -import { EuiPopover, EuiInputPopover } from '../popover'; - -const statusMap = { - unsaved: { - icon: 'dot', - color: 'accent', - tooltip: 'Changes have not been saved.', - }, - saved: { - icon: 'checkInCircleFilled', - color: 'secondary', - tooltip: 'Saved.', - }, - unchanged: { - icon: '', - color: 'secondary', - }, -}; - -export class EuiSuggestInput extends Component { - state = { - value: '', - isPopoverOpen: false, - }; - - onFieldChange = e => { - this.setState({ - value: e.target.value, - isPopoverOpen: e.target.value !== '' ? true : false, - }); - this.props.sendValue(e.target.value); - }; - - closePopover = () => { - this.setState({ - isPopoverOpen: false, - }); - }; - - render() { - const { - className, - status, - append, - tooltipContent, - suggestions, - sendValue, - ...rest - } = this.props; - - let icon; - let color; - - if (statusMap[status]) { - icon = statusMap[status].icon; - color = statusMap[status].color; - } - const classes = classNames('euiSuggestInput', className); - - // EuiFieldText's append accepts an array of elements so start by creating an empty array - const appendArray = []; - - const statusElement = (status === 'saved' || status === 'unsaved') && ( - - - - ); - - // Push the status element to the array if it is not undefined - if (statusElement) appendArray.push(statusElement); - - // Check to see if consumer passed an append item and if so, add it to the array - if (append) appendArray.push(append); - - const customInput = ( - - ); - - return ( -
- -
{suggestions}
-
-
- ); - } -} - -EuiSuggestInput.propTypes = { - className: PropTypes.string, - /** - * Status of the current query 'unsaved', 'saved', 'unchanged' or 'loading'. - */ - status: PropTypes.oneOf(['unsaved', 'saved', 'unchanged', 'loading']), - tooltipContent: PropTypes.string, - /** - * Element to be appended to the input bar. - */ - append: PropTypes.node, - /** - * List of suggestions to display using 'suggestItem'. - */ - suggestions: PropTypes.array, -}; - -EuiSuggestInput.defaultProps = { - status: 'unchanged', -}; diff --git a/src/components/suggest/suggest_input.test.js b/src/components/suggest/suggest_input.test.tsx similarity index 100% rename from src/components/suggest/suggest_input.test.js rename to src/components/suggest/suggest_input.test.tsx diff --git a/src/components/suggest/suggest_input.tsx b/src/components/suggest/suggest_input.tsx new file mode 100644 index 00000000000..b5294d41599 --- /dev/null +++ b/src/components/suggest/suggest_input.tsx @@ -0,0 +1,143 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import React, { useState, FunctionComponent } from 'react'; +import { CommonProps } from '../common'; +import classNames from 'classnames'; +// @ts-ignore +import { EuiFieldText } from '../form/field_text'; +import { EuiToolTip } from '../tool_tip'; +import { EuiIcon } from '../icon'; +import { EuiInputPopover } from '../popover'; +import { EuiSuggestItemProps } from './suggest_item'; + +export type EuiSuggestInputProps = CommonProps & { + tooltipContent?: string; + + /** + * Status of the current query 'unsaved', 'saved', 'unchanged' or 'loading'. + */ + status?: 'unsaved' | 'saved' | 'unchanged' | 'loading'; + + /** + * Element to be appended to the input bar. + */ + append?: JSX.Element; + + /** + * List of suggestions to display using 'suggestItem'. + */ + suggestions: JSX.Element[] | EuiSuggestItemProps[]; + + sendValue?: Function; +}; + +interface Status { + icon?: string; + color?: string; + tooltip?: string; +} + +interface StatusMap { + unsaved: Status; + saved: Status; + unchanged: Status; + loading: Status; +} + +const statusMap: StatusMap = { + unsaved: { + icon: 'dot', + color: 'accent', + tooltip: 'Changes have not been saved.', + }, + saved: { + icon: 'checkInCircleFilled', + color: 'secondary', + tooltip: 'Saved.', + }, + unchanged: { + icon: '', + color: 'secondary', + }, + loading: {}, +}; + +export const EuiSuggestInput: FunctionComponent< + EuiSuggestInputProps +> = props => { + const [value, setValue] = useState(''); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const { + className, + status = 'unchanged', + append, + tooltipContent, + suggestions, + sendValue, + ...rest + } = props; + + const onFieldChange = (e: any) => { + setValue(e.target.value); + setIsPopoverOpen(e.target.value !== '' ? true : false); + sendValue ? sendValue(e.target.value) : null; + }; + + const closePopover = () => { + setIsPopoverOpen(false); + }; + + let icon = ''; + let color = ''; + + if (statusMap[status]) { + icon = statusMap[status].icon || ''; + color = statusMap[status].color || ''; + } + const classes = classNames('euiSuggestInput', className); + + // EuiFieldText's append accepts an array of elements so start by creating an empty array + const appendArray = []; + + const statusElement = (status === 'saved' || status === 'unsaved') && ( + + + + ); + + // Push the status element to the array if it is not undefined + if (statusElement) appendArray.push(statusElement); + + // Check to see if consumer passed an append item and if so, add it to the array + if (append) appendArray.push(append); + + const customInput = ( + + ); + + return ( +
+ +
{suggestions}
+
+
+ ); +}; diff --git a/src/components/suggest/suggest_item.test.js b/src/components/suggest/suggest_item.test.tsx similarity index 100% rename from src/components/suggest/suggest_item.test.js rename to src/components/suggest/suggest_item.test.tsx diff --git a/src/components/suggest/suggest_item.js b/src/components/suggest/suggest_item.tsx similarity index 57% rename from src/components/suggest/suggest_item.js rename to src/components/suggest/suggest_item.tsx index 7b07559c936..5a1d5f25830 100644 --- a/src/components/suggest/suggest_item.js +++ b/src/components/suggest/suggest_item.tsx @@ -1,9 +1,55 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React, { FunctionComponent } from 'react'; +import { CommonProps } from '../common'; import classNames from 'classnames'; -import { EuiIcon, IconPropType } from '../icon'; +import { EuiIcon } from '../icon'; -const colorToClassNameMap = { +interface Type { + iconType: string; + color: string | keyof typeof colorToClassNameMap; +} + +export type EuiSuggestItemProps = CommonProps & { + /** + * Takes 'iconType' for EuiIcon and 'color'. 'color' can be tint1 through tint9. + */ + type: Type; + + /** + * Label or primary text. + */ + label: string; + + /** + * Description or secondary text (optional). + */ + description?: string; + + /** + * Label display is 'fixed' by default. Label will increase its width beyond 50% if needed with 'expand'. + */ + labelDisplay?: keyof typeof labelDisplayToClassMap; + + /** + * Handler for click on a suggestItem. + */ + onClick?: (e: React.MouseEvent) => void; +}; + +interface ColorToClassMap { + tint0: string; + tint1: string; + tint2: string; + tint3: string; + tint4: string; + tint5: string; + tint6: string; + tint7: string; + tint8: string; + tint9: string; + [key: string]: string; +} + +const colorToClassNameMap: ColorToClassMap = { tint0: 'euiSuggestItem__type--tint0', tint1: 'euiSuggestItem__type--tint1', tint2: 'euiSuggestItem__type--tint2', @@ -18,18 +64,23 @@ const colorToClassNameMap = { export const COLORS = Object.keys(colorToClassNameMap); -const labelDisplayToClassMap = { +interface LabelDisplayToClassMap { + fixed: string; + expand: string; +} + +const labelDisplayToClassMap: LabelDisplayToClassMap = { fixed: 'euiSuggestItem__labelDisplay--fixed', expand: 'euiSuggestItem__labelDisplay--expand', }; export const DISPLAYS = Object.keys(labelDisplayToClassMap); -export const EuiSuggestItem = ({ +export const EuiSuggestItem: FunctionComponent = ({ className, label, type, - labelDisplay, + labelDisplay = 'fixed', description, onClick, ...rest @@ -53,55 +104,32 @@ export const EuiSuggestItem = ({ ); if (type && type.color) { - if (COLORS.indexOf(type.color) > -1) { + if (COLORS.indexOf(type.color as string) > -1) { colorClass = colorToClassNameMap[type.color]; } } - let OuterElement = 'div'; - if (onClick) { - OuterElement = 'button'; - } - - return ( - + const innerContent = ( + {label} {description} - + ); -}; -EuiSuggestItem.propTypes = { - className: PropTypes.string, - /** - * Takes 'iconType' for EuiIcon and 'color'. 'color' can be tint1 through tint9. - */ - type: PropTypes.shape({ - iconType: IconPropType.isRequired, - color: PropTypes.oneOfType([PropTypes.oneOf(COLORS), PropTypes.string]) - .isRequired, - }).isRequired, - /** - * Label or primary text. - */ - label: PropTypes.string.isRequired, - /** - * Description or secondary text (optional). - */ - description: PropTypes.string, - /** - * Label display is 'fixed' by default. Label will increase its width beyond 50% if needed with 'expand'. - */ - labelDisplay: PropTypes.oneOf(DISPLAYS), - /** - * Handler for click on a suggestItem. - */ - onClick: PropTypes.func, -}; - -EuiSuggestItem.defaultProps = { - labelDisplay: 'fixed', + if (onClick) { + return ( + + ); + } else { + return ( +
+ {innerContent} +
+ ); + } }; From 815f3c3d63af9993d1d2cd13a9c362d839c0a60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20Franco=20Knob?= Date: Wed, 18 Dec 2019 12:47:25 -0300 Subject: [PATCH 2/4] Adds PR number to CHANGELOG line --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80ff5b56735..7ec49e7f145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## [`master`](https://github.com/elastic/eui/tree/master) - Converted `EuiHighlight` to Typescript ([#2681](https://github.com/elastic/eui/pull/2681)) -- Converted `EuiSuggest` to Typescript ([#](https://github.com/elastic/eui/pull/)) +- Converted `EuiSuggest` to Typescript ([#2692](https://github.com/elastic/eui/pull/2692)) **Bug fixes** From cd0ab6e98cf9b9d2b9cc6a8552701797b070a58f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20Knob?= Date: Fri, 27 Dec 2019 17:24:10 -0300 Subject: [PATCH 3/4] Changes Object.keys() to keysOf() --- src/components/suggest/suggest_item.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/suggest/suggest_item.tsx b/src/components/suggest/suggest_item.tsx index 5fbba27a598..84ae0643a67 100644 --- a/src/components/suggest/suggest_item.tsx +++ b/src/components/suggest/suggest_item.tsx @@ -81,7 +81,7 @@ const labelDisplayToClassMap = { expand: 'euiSuggestItem__labelDisplay--expand', }; -export const DISPLAYS = Object.keys(labelDisplayToClassMap); +export const DISPLAYS = keysOf(labelDisplayToClassMap); export const EuiSuggestItem: FunctionComponent = ({ className, From 5ddf378e146bfad39e01ef87cbfb0d214a616c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=A1vio=20Knob?= Date: Mon, 30 Dec 2019 14:46:10 -0300 Subject: [PATCH 4/4] Changes icon type to IconType --- src/components/suggest/suggest_item.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/suggest/suggest_item.tsx b/src/components/suggest/suggest_item.tsx index 84ae0643a67..cb4c3209151 100644 --- a/src/components/suggest/suggest_item.tsx +++ b/src/components/suggest/suggest_item.tsx @@ -6,10 +6,10 @@ import React, { } from 'react'; import { CommonProps, ExclusiveUnion, keysOf } from '../common'; import classNames from 'classnames'; -import { EuiIcon } from '../icon'; +import { EuiIcon, IconType } from '../icon'; interface Type { - iconType: string; + iconType: IconType; color: string | keyof typeof colorToClassNameMap; }