mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 02:40:26 -06:00
UI: Segment Input (#20904)
* Add input segment * Rename story * Cleanup * Fix lint error * More cleanup * Export ui component * Use measure text util
This commit is contained in:
parent
a533e00622
commit
047abc87c2
@ -4,6 +4,8 @@ import { SelectableValue } from '@grafana/data';
|
||||
import { SegmentSelect, useExpandableLabel, SegmentProps } from './';
|
||||
|
||||
export interface SegmentSyncProps<T> extends SegmentProps<T> {
|
||||
value?: SelectableValue<T>;
|
||||
onChange: (item: SelectableValue<T>) => void;
|
||||
options: Array<SelectableValue<T>>;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,9 @@ import { SelectableValue } from '@grafana/data';
|
||||
import { useExpandableLabel, SegmentProps } from '.';
|
||||
|
||||
export interface SegmentAsyncProps<T> extends SegmentProps<T> {
|
||||
value?: SelectableValue<T>;
|
||||
loadOptions: (query?: string) => Promise<Array<SelectableValue<T>>>;
|
||||
onChange: (item: SelectableValue<T>) => void;
|
||||
}
|
||||
|
||||
export function SegmentAsync<T>({
|
||||
|
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
const SegmentStories = storiesOf('UI/Segment/SegmentInput', module);
|
||||
import { SegmentInput } from '.';
|
||||
import { UseState } from '../../utils/storybook/UseState';
|
||||
|
||||
SegmentStories.add('Segment Input', () => {
|
||||
return (
|
||||
<UseState initialState={'some text'}>
|
||||
{(value, updateValue) => (
|
||||
<>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label width-8 query-keyword">Segment Name</span>
|
||||
</div>
|
||||
<SegmentInput
|
||||
value={value}
|
||||
onChange={text => {
|
||||
updateValue(text as string);
|
||||
action('Segment value changed')(text);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</UseState>
|
||||
);
|
||||
});
|
48
packages/grafana-ui/src/components/Segment/SegmentInput.tsx
Normal file
48
packages/grafana-ui/src/components/Segment/SegmentInput.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { cx, css } from 'emotion';
|
||||
import useClickAway from 'react-use/lib/useClickAway';
|
||||
import { measureText } from '../../utils/measureText';
|
||||
import { useExpandableLabel, SegmentProps } from '.';
|
||||
|
||||
export interface SegmentInputProps<T> extends SegmentProps<T> {
|
||||
value: string | number;
|
||||
onChange: (text: string | number) => void;
|
||||
}
|
||||
|
||||
const FONT_SIZE = 14;
|
||||
|
||||
export function SegmentInput<T>({
|
||||
value,
|
||||
onChange,
|
||||
Component,
|
||||
className,
|
||||
}: React.PropsWithChildren<SegmentInputProps<T>>) {
|
||||
const ref = useRef(null);
|
||||
const [inputWidth, setInputWidth] = useState<number>(measureText(value.toString(), FONT_SIZE).width);
|
||||
const [Label, , expanded, setExpanded] = useExpandableLabel(false);
|
||||
useClickAway(ref, () => setExpanded(false));
|
||||
|
||||
if (!expanded) {
|
||||
return <Label Component={Component || <a className={cx('gf-form-label', 'query-part', className)}>{value}</a>} />;
|
||||
}
|
||||
|
||||
const inputWidthStyle = css`
|
||||
width: ${Math.max(inputWidth + 20, 32)}px;
|
||||
`;
|
||||
|
||||
return (
|
||||
<input
|
||||
ref={ref}
|
||||
autoFocus
|
||||
className={cx(`gf-form gf-form-input`, inputWidthStyle)}
|
||||
value={value}
|
||||
onChange={item => {
|
||||
const { width } = measureText(item.target.value, FONT_SIZE);
|
||||
setInputWidth(width);
|
||||
onChange(item.target.value);
|
||||
}}
|
||||
onBlur={() => setExpanded(false)}
|
||||
onKeyDown={e => [13, 27].includes(e.keyCode) && setExpanded(false)}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
export { Segment } from './Segment';
|
||||
export { SegmentAsync } from './SegmentAsync';
|
||||
export { SegmentSelect } from './SegmentSelect';
|
||||
export { SegmentInput } from './SegmentInput';
|
||||
export { SegmentProps } from './types';
|
||||
export { useExpandableLabel } from './useExpandableLabel';
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { ReactElement } from 'react';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
export interface SegmentProps<T> {
|
||||
onChange: (item: SelectableValue<T>) => void;
|
||||
value?: SelectableValue<T>;
|
||||
Component?: ReactElement;
|
||||
className?: string;
|
||||
allowCustomValue?: boolean;
|
||||
|
@ -105,7 +105,7 @@ export { DataSourceHttpSettings } from './DataSourceSettings/DataSourceHttpSetti
|
||||
export { Spinner } from './Spinner/Spinner';
|
||||
export { FadeTransition } from './transitions/FadeTransition';
|
||||
export { SlideOutTransition } from './transitions/SlideOutTransition';
|
||||
export { Segment, SegmentAsync, SegmentSelect } from './Segment/';
|
||||
export { Segment, SegmentAsync, SegmentInput, SegmentSelect } from './Segment/';
|
||||
export { default as Chart } from './Chart';
|
||||
export { Icon } from './Icon/Icon';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user