Field/panel options - do not trigger change events onChange, but onBlur or enter key press (#24388)

* Field options - do not trigger change events onChange, but onBlur or enter key press

* Review changes

* fix ts
This commit is contained in:
Dominik Prokop 2020-05-07 16:07:49 +02:00 committed by GitHub
parent bb436e7447
commit 07fc248626
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 26 deletions

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useCallback } from 'react';
import { import {
FieldConfigEditorProps, FieldConfigEditorProps,
toIntegerOrUndefined, toIntegerOrUndefined,
@ -13,19 +13,42 @@ export const NumberValueEditor: React.FC<FieldConfigEditorProps<number, NumberFi
item, item,
}) => { }) => {
const { settings } = item; const { settings } = item;
const onValueChange = useCallback(
(e: React.SyntheticEvent) => {
if (e.hasOwnProperty('key')) {
// handling keyboard event
const evt = e as React.KeyboardEvent<HTMLInputElement>;
if (evt.key === 'Enter') {
onChange(
settings?.integer
? toIntegerOrUndefined(evt.currentTarget.value)
: toFloatOrUndefined(evt.currentTarget.value)
);
}
} else {
// handling form event
const evt = e as React.FormEvent<HTMLInputElement>;
onChange(
settings?.integer
? toIntegerOrUndefined(evt.currentTarget.value)
: toFloatOrUndefined(evt.currentTarget.value)
);
}
},
[onChange]
);
return ( return (
<Input <Input
value={isNaN(value) ? '' : value} defaultValue={isNaN(value) ? '' : value.toString()}
min={settings?.min} min={settings?.min}
max={settings?.max} max={settings?.max}
type="number" type="number"
step={settings?.step} step={settings?.step}
placeholder={settings?.placeholder} placeholder={settings?.placeholder}
onChange={e => { onBlur={onValueChange}
onChange( onKeyDown={onValueChange}
settings?.integer ? toIntegerOrUndefined(e.currentTarget.value) : toFloatOrUndefined(e.currentTarget.value)
);
}}
/> />
); );
}; };

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useCallback } from 'react';
import { FieldConfigEditorProps, StringFieldConfigSettings } from '@grafana/data'; import { FieldConfigEditorProps, StringFieldConfigSettings } from '@grafana/data';
import { Input } from '../Input/Input'; import { Input } from '../Input/Input';
import { TextArea } from '../TextArea/TextArea'; import { TextArea } from '../TextArea/TextArea';
@ -9,14 +9,31 @@ export const StringValueEditor: React.FC<FieldConfigEditorProps<string, StringFi
item, item,
}) => { }) => {
const Component = item.settings?.useTextarea ? TextArea : Input; const Component = item.settings?.useTextarea ? TextArea : Input;
const onValueChange = useCallback(
(e: React.SyntheticEvent) => {
if (e.hasOwnProperty('key')) {
// handling keyboard event
const evt = e as React.KeyboardEvent<HTMLInputElement>;
if (evt.key === 'Enter' && !item.settings?.useTextarea) {
onChange(evt.currentTarget.value.trim() === '' ? undefined : evt.currentTarget.value);
}
} else {
// handling form event
const evt = e as React.FormEvent<HTMLInputElement>;
onChange(evt.currentTarget.value.trim() === '' ? undefined : evt.currentTarget.value);
}
},
[onChange]
);
return ( return (
<Component <Component
placeholder={item.settings?.placeholder} placeholder={item.settings?.placeholder}
value={value || ''} defaultValue={value || ''}
rows={item.settings?.useTextarea && item.settings.rows} rows={item.settings?.useTextarea && item.settings.rows}
onChange={(e: React.FormEvent<any>) => onBlur={onValueChange}
onChange(e.currentTarget.value.trim() === '' ? undefined : e.currentTarget.value) onKeyDown={onValueChange}
}
/> />
); );
}; };

View File

@ -1,4 +1,4 @@
import React, { ChangeEvent } from 'react'; import React from 'react';
import { HorizontalGroup } from '../Layout/Layout'; import { HorizontalGroup } from '../Layout/Layout';
import { IconButton, Label, RadioButtonGroup } from '../index'; import { IconButton, Label, RadioButtonGroup } from '../index';
import { Field } from '../Forms/Field'; import { Field } from '../Forms/Field';
@ -19,41 +19,61 @@ const MAPPING_OPTIONS: Array<SelectableValue<MappingType>> = [
export const MappingRow: React.FC<Props> = ({ valueMapping, updateValueMapping, removeValueMapping }) => { export const MappingRow: React.FC<Props> = ({ valueMapping, updateValueMapping, removeValueMapping }) => {
const { type } = valueMapping; const { type } = valueMapping;
const onMappingValueChange = (event: ChangeEvent<HTMLInputElement>) => { const onMappingValueChange = (value: string) => {
updateValueMapping({ ...valueMapping, value: event.target.value }); updateValueMapping({ ...valueMapping, value: value });
}; };
const onMappingFromChange = (event: ChangeEvent<HTMLInputElement>) => { const onMappingFromChange = (value: string) => {
updateValueMapping({ ...valueMapping, from: event.target.value }); updateValueMapping({ ...valueMapping, from: value });
}; };
const onMappingToChange = (event: ChangeEvent<HTMLInputElement>) => { const onMappingToChange = (value: string) => {
updateValueMapping({ ...valueMapping, to: event.target.value }); updateValueMapping({ ...valueMapping, to: value });
}; };
const onMappingTextChange = (event: ChangeEvent<HTMLInputElement>) => { const onMappingTextChange = (value: string) => {
updateValueMapping({ ...valueMapping, text: event.target.value }); updateValueMapping({ ...valueMapping, text: value });
}; };
const onMappingTypeChange = (mappingType: MappingType) => { const onMappingTypeChange = (mappingType: MappingType) => {
updateValueMapping({ ...valueMapping, type: mappingType }); updateValueMapping({ ...valueMapping, type: mappingType });
}; };
const onKeyDown = (handler: (value: string) => void) => (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
handler(e.currentTarget.value);
}
};
const renderRow = () => { const renderRow = () => {
if (type === MappingType.RangeToText) { if (type === MappingType.RangeToText) {
return ( return (
<> <>
<HorizontalGroup> <HorizontalGroup>
<Field label="From"> <Field label="From">
<Input type="number" defaultValue={(valueMapping as RangeMap).from!} onBlur={onMappingFromChange} /> <Input
type="number"
defaultValue={(valueMapping as RangeMap).from!}
onBlur={e => onMappingFromChange(e.currentTarget.value)}
onKeyDown={onKeyDown(onMappingFromChange)}
/>
</Field> </Field>
<Field label="To"> <Field label="To">
<Input type="number" defaultValue={(valueMapping as RangeMap).to} onBlur={onMappingToChange} /> <Input
type="number"
defaultValue={(valueMapping as RangeMap).to}
onBlur={e => onMappingToChange(e.currentTarget.value)}
onKeyDown={onKeyDown(onMappingToChange)}
/>
</Field> </Field>
</HorizontalGroup> </HorizontalGroup>
<Field label="Text"> <Field label="Text">
<Input defaultValue={valueMapping.text} onBlur={onMappingTextChange} /> <Input
defaultValue={valueMapping.text}
onBlur={e => onMappingTextChange(e.currentTarget.value)}
onKeyDown={onKeyDown(onMappingTextChange)}
/>
</Field> </Field>
</> </>
); );
@ -62,11 +82,20 @@ export const MappingRow: React.FC<Props> = ({ valueMapping, updateValueMapping,
return ( return (
<> <>
<Field label="Value"> <Field label="Value">
<Input type="number" defaultValue={(valueMapping as ValueMap).value} onBlur={onMappingValueChange} /> <Input
type="number"
defaultValue={(valueMapping as ValueMap).value}
onBlur={e => onMappingValueChange(e.currentTarget.value)}
onKeyDown={onKeyDown(onMappingValueChange)}
/>
</Field> </Field>
<Field label="Text"> <Field label="Text">
<Input defaultValue={valueMapping.text} onBlur={onMappingTextChange} /> <Input
defaultValue={valueMapping.text}
onBlur={e => onMappingTextChange(e.currentTarget.value)}
onKeyDown={onKeyDown(onMappingTextChange)}
/>
</Field> </Field>
</> </>
); );