Skip to content

Commit f06a48b

Browse files
committed
[Maps] convert vector style component to typescript round 1
1 parent 2c1bc50 commit f06a48b

5 files changed

Lines changed: 141 additions & 82 deletions

File tree

x-pack/plugins/maps/public/classes/styles/vector/components/color/vector_style_color_editor.js renamed to x-pack/plugins/maps/public/classes/styles/vector/components/color/vector_style_color_editor.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@
66

77
import React from 'react';
88

9-
import { StylePropEditor } from '../style_prop_editor';
9+
import { i18n } from '@kbn/i18n';
10+
import { Props, StylePropEditor } from '../style_prop_editor';
11+
// @ts-expect-error
1012
import { DynamicColorForm } from './dynamic_color_form';
13+
// @ts-expect-error
1114
import { StaticColorForm } from './static_color_form';
12-
import { i18n } from '@kbn/i18n';
15+
import { ColorDynamicOptions, ColorStaticOptions } from '../../../../../../common/descriptor_types';
1316

14-
export function VectorStyleColorEditor(props) {
17+
export function VectorStyleColorEditor(props: Props<ColorStaticOptions, ColorDynamicOptions>) {
1518
const colorForm = props.styleProperty.isDynamic() ? (
1619
<DynamicColorForm {...props} />
1720
) : (
1821
<StaticColorForm {...props} />
1922
);
2023

2124
return (
22-
<StylePropEditor
25+
<StylePropEditor<ColorStaticOptions, ColorDynamicOptions>
2326
{...props}
2427
customStaticOptionLabel={i18n.translate(
2528
'xpack.maps.styles.color.staticDynamicSelect.staticLabel',

x-pack/plugins/maps/public/classes/styles/vector/components/field_select.js renamed to x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,50 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import PropTypes from 'prop-types';
87
import React from 'react';
98

10-
import { EuiComboBox, EuiHighlight, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
11-
import { FIELD_ORIGIN } from '../../../../../common/constants';
9+
import {
10+
EuiComboBox,
11+
EuiComboBoxProps,
12+
EuiComboBoxOptionOption,
13+
EuiHighlight,
14+
EuiFlexGroup,
15+
EuiFlexItem,
16+
} from '@elastic/eui';
1217
import { i18n } from '@kbn/i18n';
18+
import { FIELD_ORIGIN, VECTOR_STYLES } from '../../../../../common/constants';
1319
import { FieldIcon } from '../../../../../../../../src/plugins/kibana_react/public';
20+
import { StyleField } from '../style_fields_helper';
1421

15-
function renderOption(option, searchValue, contentClassName) {
22+
function renderOption(
23+
option: EuiComboBoxOptionOption<StyleField>,
24+
searchValue: string,
25+
contentClassName: string
26+
) {
27+
const fieldIcon = option.value ? <FieldIcon type={option.value.type} fill="none" /> : null;
1628
return (
1729
<EuiFlexGroup className={contentClassName} gutterSize="s" alignItems="center">
18-
<EuiFlexItem grow={null}>
19-
<FieldIcon type={option.value.type} fill="none" />
20-
</EuiFlexItem>
30+
<EuiFlexItem grow={null}>{fieldIcon}</EuiFlexItem>
2131
<EuiFlexItem>
2232
<EuiHighlight search={searchValue}>{option.label}</EuiHighlight>
2333
</EuiFlexItem>
2434
</EuiFlexGroup>
2535
);
2636
}
2737

28-
function groupFieldsByOrigin(fields) {
29-
const fieldsByOriginMap = new Map();
38+
function groupFieldsByOrigin(fields: StyleField[]) {
39+
const fieldsByOriginMap = new Map<FIELD_ORIGIN, StyleField[]>();
3040
fields.forEach((field) => {
3141
if (fieldsByOriginMap.has(field.origin)) {
3242
const fieldsList = fieldsByOriginMap.get(field.origin);
33-
fieldsList.push(field);
34-
fieldsByOriginMap.set(field.origin, fieldsList);
43+
fieldsList!.push(field);
44+
fieldsByOriginMap.set(field.origin, fieldsList!);
3545
} else {
3646
fieldsByOriginMap.set(field.origin, [field]);
3747
}
3848
});
3949

40-
function fieldsListToOptions(fieldsList) {
50+
function fieldsListToOptions(fieldsList: StyleField[]) {
4151
return fieldsList
4252
.map((field) => {
4353
return { value: field, label: field.label };
@@ -51,10 +61,13 @@ function groupFieldsByOrigin(fields) {
5161
// do not show origin group if all fields are from same origin
5262
const onlyOriginKey = fieldsByOriginMap.keys().next().value;
5363
const fieldsList = fieldsByOriginMap.get(onlyOriginKey);
54-
return fieldsListToOptions(fieldsList);
64+
return fieldsListToOptions(fieldsList!);
5565
}
5666

57-
const optionGroups = [];
67+
const optionGroups: Array<{
68+
label: string;
69+
options: Array<EuiComboBoxOptionOption<StyleField>>;
70+
}> = [];
5871
fieldsByOriginMap.forEach((fieldsList, fieldOrigin) => {
5972
optionGroups.push({
6073
label: i18n.translate('xpack.maps.style.fieldSelect.OriginLabel', {
@@ -65,29 +78,46 @@ function groupFieldsByOrigin(fields) {
6578
});
6679
});
6780

68-
optionGroups.sort((a, b) => {
69-
return a.label.toLowerCase().localeCompare(b.label.toLowerCase());
70-
});
81+
optionGroups.sort(
82+
(a: EuiComboBoxOptionOption<StyleField>, b: EuiComboBoxOptionOption<StyleField>) => {
83+
return a.label.toLowerCase().localeCompare(b.label.toLowerCase());
84+
}
85+
);
7186

7287
return optionGroups;
7388
}
7489

75-
export function FieldSelect({ fields, selectedFieldName, onChange, styleName, ...rest }) {
76-
const onFieldChange = (selectedFields) => {
90+
type Props = {
91+
fields: StyleField[];
92+
selectedFieldName: string;
93+
onChange: ({ field }: { field: StyleField | null }) => void;
94+
styleName: VECTOR_STYLES;
95+
} & Omit<
96+
EuiComboBoxProps<StyleField>,
97+
| 'selectedOptions'
98+
| 'options'
99+
| 'onChange'
100+
| 'singleSelection'
101+
| 'isClearable'
102+
| 'fullWidth'
103+
| 'renderOption'
104+
>;
105+
106+
export function FieldSelect({ fields, selectedFieldName, onChange, styleName, ...rest }: Props) {
107+
const onFieldChange = (selectedFields: Array<EuiComboBoxOptionOption<StyleField>>) => {
77108
onChange({
78-
field: selectedFields.length > 0 ? selectedFields[0].value : null,
109+
field: selectedFields.length > 0 && selectedFields[0].value ? selectedFields[0].value : null,
79110
});
80111
};
81112

82113
let selectedOption;
83114
if (selectedFieldName) {
84-
const field = fields.find((field) => {
85-
return field.name === selectedFieldName;
115+
const field = fields.find((f) => {
116+
return f.name === selectedFieldName;
86117
});
87-
//Do not spread in all the other unused values (e.g. type, supportsAutoDomain etc...)
88118
if (field) {
89119
selectedOption = {
90-
value: field.value,
120+
value: field,
91121
label: field.label,
92122
};
93123
}
@@ -110,15 +140,3 @@ export function FieldSelect({ fields, selectedFieldName, onChange, styleName, ..
110140
/>
111141
);
112142
}
113-
114-
export const fieldShape = PropTypes.shape({
115-
name: PropTypes.string.isRequired,
116-
origin: PropTypes.oneOf(Object.values(FIELD_ORIGIN)).isRequired,
117-
type: PropTypes.string.isRequired,
118-
});
119-
120-
FieldSelect.propTypes = {
121-
selectedFieldName: PropTypes.string,
122-
fields: PropTypes.arrayOf(fieldShape).isRequired,
123-
onChange: PropTypes.func.isRequired,
124-
};

x-pack/plugins/maps/public/classes/styles/vector/components/get_vector_style_label.js renamed to x-pack/plugins/maps/public/classes/styles/vector/components/get_vector_style_label.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ import { i18n } from '@kbn/i18n';
88

99
import { VECTOR_STYLES } from '../../../../../common/constants';
1010

11-
export function getDisabledByMessage(styleName) {
11+
export function getDisabledByMessage(styleName: VECTOR_STYLES) {
1212
return i18n.translate('xpack.maps.styles.vector.disabledByMessage', {
1313
defaultMessage: `Set '{styleLabel}' to enable`,
1414
values: { styleLabel: getVectorStyleLabel(styleName) },
1515
});
1616
}
1717

18-
export function getVectorStyleLabel(styleName) {
18+
export function getVectorStyleLabel(styleName: VECTOR_STYLES) {
1919
switch (styleName) {
2020
case VECTOR_STYLES.FILL_COLOR:
2121
return i18n.translate('xpack.maps.styles.vector.fillColorLabel', {

x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.js renamed to x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.tsx

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,37 @@
55
*/
66

77
import _ from 'lodash';
8-
import React, { Component } from 'react';
8+
import React, { ChangeEvent, Component } from 'react';
9+
import { EuiComboBox, EuiComboBoxOptionOption, EuiFieldText } from '@elastic/eui';
10+
import { IField } from '../../../fields/field';
11+
12+
interface Props {
13+
dataTestSubj: string;
14+
field: IField;
15+
getValueSuggestions: (query: string) => Promise<string[]>;
16+
onChange: (value: string) => void;
17+
value: string;
18+
}
19+
20+
interface State {
21+
suggestions: string[];
22+
isLoadingSuggestions: boolean;
23+
hasPrevFocus: boolean;
24+
fieldDataType: string | null;
25+
localFieldTextValue: string;
26+
searchValue?: string;
27+
}
928

10-
import { EuiComboBox, EuiFieldText } from '@elastic/eui';
29+
export class StopInput extends Component<Props, State> {
30+
private _isMounted: boolean = false;
1131

12-
export class StopInput extends Component {
13-
constructor(props) {
32+
constructor(props: Props) {
1433
super(props);
1534
this.state = {
1635
suggestions: [],
1736
isLoadingSuggestions: false,
1837
hasPrevFocus: false,
19-
fieldDataType: undefined,
38+
fieldDataType: null,
2039
localFieldTextValue: props.value,
2140
};
2241
}
@@ -45,15 +64,15 @@ export class StopInput extends Component {
4564
}
4665
};
4766

48-
_onChange = (selectedOptions) => {
67+
_onChange = (selectedOptions: Array<EuiComboBoxOptionOption<string>>) => {
4968
this.props.onChange(_.get(selectedOptions, '[0].label', ''));
5069
};
5170

52-
_onCreateOption = (newValue) => {
71+
_onCreateOption = (newValue: string) => {
5372
this.props.onChange(newValue);
5473
};
5574

56-
_onSearchChange = async (searchValue) => {
75+
_onSearchChange = async (searchValue: string) => {
5776
this.setState(
5877
{
5978
isLoadingSuggestions: true,
@@ -65,8 +84,8 @@ export class StopInput extends Component {
6584
);
6685
};
6786

68-
_loadSuggestions = _.debounce(async (searchValue) => {
69-
let suggestions = [];
87+
_loadSuggestions = _.debounce(async (searchValue: string) => {
88+
let suggestions: string[] = [];
7089
try {
7190
suggestions = await this.props.getValueSuggestions(searchValue);
7291
} catch (error) {
@@ -81,7 +100,7 @@ export class StopInput extends Component {
81100
}
82101
}, 300);
83102

84-
_onFieldTextChange = (event) => {
103+
_onFieldTextChange = (event: ChangeEvent<HTMLInputElement>) => {
85104
this.setState({ localFieldTextValue: event.target.value });
86105
// onChange can cause UI lag, ensure smooth input typing by debouncing onChange
87106
this._debouncedOnFieldTextChange();

x-pack/plugins/maps/public/classes/styles/vector/components/style_prop_editor.js renamed to x-pack/plugins/maps/public/classes/styles/vector/components/style_prop_editor.tsx

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import React, { Component, Fragment } from 'react';
8-
import { getVectorStyleLabel, getDisabledByMessage } from './get_vector_style_label';
7+
import React, { Component, Fragment, ReactElement } from 'react';
98
import {
109
EuiFormRow,
1110
EuiSelect,
@@ -14,12 +13,31 @@ import {
1413
EuiFieldText,
1514
EuiToolTip,
1615
} from '@elastic/eui';
17-
import { STYLE_TYPE } from '../../../../../common/constants';
1816
import { i18n } from '@kbn/i18n';
17+
import { getVectorStyleLabel, getDisabledByMessage } from './get_vector_style_label';
18+
import { STYLE_TYPE, VECTOR_STYLES } from '../../../../../common/constants';
19+
import { FieldMetaOptions } from '../../../../../common/descriptor_types';
20+
import { IStyleProperty } from '../properties/style_property';
21+
import { StyleField } from '../style_fields_helper';
22+
23+
export interface Props<StaticOptionsType, DynamicOptionsType> {
24+
children: ReactElement<any>;
25+
customStaticOptionLabel?: string;
26+
defaultStaticStyleOptions: StaticOptionsType;
27+
defaultDynamicStyleOptions: DynamicOptionsType;
28+
disabled: boolean;
29+
disabledBy?: VECTOR_STYLES;
30+
fields: StyleField[];
31+
onDynamicStyleChange: (propertyName: VECTOR_STYLES, options: DynamicOptionsType) => void;
32+
onStaticStyleChange: (propertyName: VECTOR_STYLES, options: StaticOptionsType) => void;
33+
styleProperty: IStyleProperty<any>;
34+
}
1935

20-
export class StylePropEditor extends Component {
21-
_prevStaticStyleOptions = this.props.defaultStaticStyleOptions;
22-
_prevDynamicStyleOptions = this.props.defaultDynamicStyleOptions;
36+
export class StylePropEditor<StaticOptionsType, DynamicOptionsType> extends Component<
37+
Props<StaticOptionsType, DynamicOptionsType>
38+
> {
39+
private _prevStaticStyleOptions = this.props.defaultStaticStyleOptions;
40+
private _prevDynamicStyleOptions = this.props.defaultDynamicStyleOptions;
2341

2442
_onTypeToggle = () => {
2543
if (this.props.styleProperty.isDynamic()) {
@@ -41,7 +59,7 @@ export class StylePropEditor extends Component {
4159
}
4260
};
4361

44-
_onFieldMetaOptionsChange = (fieldMetaOptions) => {
62+
_onFieldMetaOptionsChange = (fieldMetaOptions: FieldMetaOptions) => {
4563
const options = {
4664
...this.props.styleProperty.getOptions(),
4765
fieldMetaOptions,
@@ -89,28 +107,29 @@ export class StylePropEditor extends Component {
89107

90108
const staticDynamicSelect = this.renderStaticDynamicSelect();
91109

92-
const stylePropertyForm = this.props.disabled ? (
93-
<EuiToolTip
94-
anchorClassName="mapStyleFormDisabledTooltip"
95-
content={getDisabledByMessage(this.props.disabledBy)}
96-
>
97-
<EuiFlexGroup gutterSize="xs">
98-
<EuiFlexItem grow={false} className="mapStyleSettings__fixedBox">
99-
{staticDynamicSelect}
100-
</EuiFlexItem>
101-
<EuiFlexItem>
102-
<EuiFieldText compressed disabled />
103-
</EuiFlexItem>
104-
</EuiFlexGroup>
105-
</EuiToolTip>
106-
) : (
107-
<Fragment>
108-
{React.cloneElement(this.props.children, {
109-
staticDynamicSelect,
110-
})}
111-
{fieldMetaOptionsPopover}
112-
</Fragment>
113-
);
110+
const stylePropertyForm =
111+
this.props.disabled && this.props.disabledBy ? (
112+
<EuiToolTip
113+
anchorClassName="mapStyleFormDisabledTooltip"
114+
content={getDisabledByMessage(this.props.disabledBy)}
115+
>
116+
<EuiFlexGroup gutterSize="xs">
117+
<EuiFlexItem grow={false} className="mapStyleSettings__fixedBox">
118+
{staticDynamicSelect}
119+
</EuiFlexItem>
120+
<EuiFlexItem>
121+
<EuiFieldText compressed disabled />
122+
</EuiFlexItem>
123+
</EuiFlexGroup>
124+
</EuiToolTip>
125+
) : (
126+
<Fragment>
127+
{React.cloneElement(this.props.children, {
128+
staticDynamicSelect,
129+
})}
130+
{fieldMetaOptionsPopover}
131+
</Fragment>
132+
);
114133

115134
return (
116135
<EuiFormRow

0 commit comments

Comments
 (0)