mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
UX: Fix empty space in select (#19713)
This commit is contained in:
38
packages/grafana-ui/src/components/Select/Select.story.tsx
Normal file
38
packages/grafana-ui/src/components/Select/Select.story.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { withKnobs, object } from '@storybook/addon-knobs';
|
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { UseState } from '../../utils/storybook/UseState';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Select } from './Select';
|
||||
|
||||
const SelectStories = storiesOf('UI/Select/Select', module);
|
||||
|
||||
SelectStories.addDecorator(withCenteredStory).addDecorator(withKnobs);
|
||||
|
||||
SelectStories.add('default', () => {
|
||||
const intialState: SelectableValue<string> = { label: 'A label', value: 'A value' };
|
||||
const value = object<SelectableValue<string>>('Selected Value:', intialState);
|
||||
const options = object<Array<SelectableValue<string>>>('Options:', [
|
||||
intialState,
|
||||
{ label: 'Another label', value: 'Another value' },
|
||||
]);
|
||||
|
||||
return (
|
||||
<UseState initialState={value}>
|
||||
{(value, updateValue) => {
|
||||
return (
|
||||
<Select
|
||||
value={value}
|
||||
options={options}
|
||||
onChange={value => {
|
||||
action('onChanged fired')(value);
|
||||
updateValue(value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</UseState>
|
||||
);
|
||||
});
|
||||
@@ -7,6 +7,7 @@ import { components } from '@torkelo/react-select';
|
||||
import { FadeTransition, Spinner } from '..';
|
||||
import { useDelayedSwitch } from '../../utils/useDelayedSwitch';
|
||||
import { stylesFactory } from '../../themes';
|
||||
import { SlideOutTransition } from '../transitions/SlideOutTransition';
|
||||
|
||||
const getStyles = stylesFactory(() => {
|
||||
const container = css`
|
||||
@@ -16,6 +17,7 @@ const getStyles = stylesFactory(() => {
|
||||
margin-right: 10px;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const item = css`
|
||||
@@ -44,18 +46,32 @@ export const SingleValue = (props: Props) => {
|
||||
return (
|
||||
<components.SingleValue {...props}>
|
||||
<div className={cx('gf-form-select-box__img-value')}>
|
||||
<div className={styles.container}>
|
||||
<FadeTransition duration={150} visible={loading}>
|
||||
<Spinner className={styles.item} inline />
|
||||
</FadeTransition>
|
||||
{data.imgUrl && (
|
||||
<FadeTransition duration={150} visible={!loading}>
|
||||
<img className={styles.item} src={data.imgUrl} />
|
||||
</FadeTransition>
|
||||
)}
|
||||
</div>
|
||||
{data.imgUrl ? (
|
||||
<FadeWithImage loading={loading} imgUrl={data.imgUrl} />
|
||||
) : (
|
||||
<SlideOutTransition horizontal size={16} visible={loading} duration={150}>
|
||||
<div className={styles.container}>
|
||||
<Spinner className={styles.item} inline />
|
||||
</div>
|
||||
</SlideOutTransition>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</components.SingleValue>
|
||||
);
|
||||
};
|
||||
|
||||
const FadeWithImage = (props: { loading: boolean; imgUrl: string }) => {
|
||||
const styles = getStyles();
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<FadeTransition duration={150} visible={props.loading}>
|
||||
<Spinner className={styles.item} inline />
|
||||
</FadeTransition>
|
||||
<FadeTransition duration={150} visible={!props.loading}>
|
||||
<img className={styles.item} src={props.imgUrl} />
|
||||
</FadeTransition>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -89,6 +89,6 @@ export { ErrorBoundary, ErrorBoundaryAlert } from './ErrorBoundary/ErrorBoundary
|
||||
export { AlphaNotice } from './AlphaNotice/AlphaNotice';
|
||||
export { Spinner } from './Spinner/Spinner';
|
||||
export { FadeTransition } from './transitions/FadeTransition';
|
||||
|
||||
export { SlideOutTransition } from './transitions/SlideOutTransition';
|
||||
// Segment
|
||||
export { Segment, SegmentAsync, SegmentSelect } from './Segment/';
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { CSSTransition } from 'react-transition-group';
|
||||
import { stylesFactory } from '../../themes';
|
||||
|
||||
const getStyles = stylesFactory((duration: number, measurement: 'width' | 'height', size: number) => {
|
||||
return {
|
||||
enter: css`
|
||||
label: enter;
|
||||
${measurement}: 0;
|
||||
opacity: 0;
|
||||
`,
|
||||
enterActive: css`
|
||||
label: enterActive;
|
||||
${measurement}: ${size}px;
|
||||
opacity: 1;
|
||||
transition: opacity ${duration}ms ease-out, ${measurement} ${duration}ms ease-out;
|
||||
`,
|
||||
exit: css`
|
||||
label: exit;
|
||||
${measurement}: ${size}px;
|
||||
opacity: 1;
|
||||
`,
|
||||
exitActive: css`
|
||||
label: exitActive;
|
||||
opacity: 0;
|
||||
${measurement}: 0;
|
||||
transition: opacity ${duration}ms ease-out, ${measurement} ${duration}ms ease-out;
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
visible: boolean;
|
||||
size: number;
|
||||
|
||||
duration?: number;
|
||||
horizontal?: boolean;
|
||||
};
|
||||
|
||||
export function SlideOutTransition(props: Props) {
|
||||
const { visible, children, duration = 250, horizontal, size } = props;
|
||||
const styles = getStyles(duration, horizontal ? 'width' : 'height', size);
|
||||
return (
|
||||
<CSSTransition in={visible} mountOnEnter={true} unmountOnExit={true} timeout={duration} classNames={styles}>
|
||||
{children}
|
||||
</CSSTransition>
|
||||
);
|
||||
}
|
||||
@@ -318,9 +318,6 @@ Array [
|
||||
<div
|
||||
className="gf-form-select-box__img-value"
|
||||
>
|
||||
<div
|
||||
className="css-zyq2zu"
|
||||
/>
|
||||
stackdriver auto
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user