Grafana-UI: Add disabled state to picker components (#34005)

* TimeRangeInput: add disabled prop

* TimeOfDayPicker: add disabled prop

* TimeZonePicker: add disabled prop

* TagsInput: add disabled prop
This commit is contained in:
Alex Khomenko 2021-05-12 18:33:36 +03:00 committed by GitHub
parent 6200c40160
commit 167bad070b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 47 deletions

View File

@ -145,6 +145,10 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
inputDisabled: css` inputDisabled: css`
background-color: ${theme.colors.action.disabledBackground}; background-color: ${theme.colors.action.disabledBackground};
color: ${theme.colors.action.disabledText}; color: ${theme.colors.action.disabledText};
border: 1px solid ${theme.colors.action.disabledBackground};
&:focus {
box-shadow: none;
}
`, `,
addon: css` addon: css`
label: input-addon; label: input-addon;

View File

@ -12,6 +12,7 @@ export interface Props {
onChange: (tags: string[]) => void; onChange: (tags: string[]) => void;
width?: number; width?: number;
className?: string; className?: string;
disabled?: boolean;
} }
export const TagsInput: FC<Props> = ({ export const TagsInput: FC<Props> = ({
@ -20,6 +21,7 @@ export const TagsInput: FC<Props> = ({
onChange, onChange,
width, width,
className, className,
disabled,
}) => { }) => {
const [newTagName, setNewName] = useState(''); const [newTagName, setNewName] = useState('');
const styles = useStyles(getStyles); const styles = useStyles(getStyles);
@ -58,6 +60,7 @@ export const TagsInput: FC<Props> = ({
</div> </div>
<div> <div>
<Input <Input
disabled={disabled}
placeholder={placeholder} placeholder={placeholder}
onChange={onNameChange} onChange={onNameChange}
value={newTagName} value={newTagName}

View File

@ -2,7 +2,7 @@ import React, { FC } from 'react';
import RcTimePicker from 'rc-time-picker'; import RcTimePicker from 'rc-time-picker';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { dateTime, DateTime, dateTimeAsMoment, GrafanaTheme } from '@grafana/data'; import { dateTime, DateTime, dateTimeAsMoment, GrafanaTheme } from '@grafana/data';
import { useTheme, Icon } from '../../index'; import { Icon, useStyles } from '../../index';
import { stylesFactory } from '../../themes'; import { stylesFactory } from '../../themes';
import { inputSizes } from '../Forms/commonStyles'; import { inputSizes } from '../Forms/commonStyles';
import { FormInputSize } from '../Forms/types'; import { FormInputSize } from '../Forms/types';
@ -14,8 +14,48 @@ export interface Props {
showHour?: boolean; showHour?: boolean;
minuteStep?: number; minuteStep?: number;
size?: FormInputSize; size?: FormInputSize;
disabled?: boolean;
} }
export const TimeOfDayPicker: FC<Props> = ({
minuteStep = 1,
showHour = true,
onChange,
value,
size = 'auto',
disabled,
}) => {
const styles = useStyles(getStyles);
return (
<RcTimePicker
className={cx(inputSizes()[size], styles.input)}
popupClassName={styles.picker}
defaultValue={dateTimeAsMoment()}
onChange={(value: any) => onChange(dateTime(value))}
allowEmpty={false}
showSecond={false}
value={dateTimeAsMoment(value)}
showHour={showHour}
minuteStep={minuteStep}
inputIcon={<Caret wrapperStyle={styles.caretWrapper} />}
disabled={disabled}
/>
);
};
interface CaretProps {
wrapperStyle?: string;
}
const Caret: FC<CaretProps> = ({ wrapperStyle = '' }) => {
return (
<div className={wrapperStyle}>
<Icon name="angle-down" />
</div>
);
};
const getStyles = stylesFactory((theme: GrafanaTheme) => { const getStyles = stylesFactory((theme: GrafanaTheme) => {
const bgColor = theme.colors.formInputBg; const bgColor = theme.colors.formInputBg;
const menuShadowColor = theme.colors.dropdownShadow; const menuShadowColor = theme.colors.dropdownShadow;
@ -79,40 +119,16 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
&:focus { &:focus {
${focusCss(theme)} ${focusCss(theme)}
} }
&:disabled {
background-color: ${theme.colors.formInputBgDisabled};
color: ${theme.colors.formInputDisabledText};
border: 1px solid ${theme.colors.formInputBgDisabled};
&:focus {
box-shadow: none;
}
}
} }
`, `,
}; };
}); });
export const TimeOfDayPicker: FC<Props> = ({ minuteStep = 1, showHour = true, onChange, value, size = 'auto' }) => {
const theme = useTheme();
const styles = getStyles(theme);
return (
<div>
<RcTimePicker
className={cx(inputSizes()[size], styles.input)}
popupClassName={styles.picker}
defaultValue={dateTimeAsMoment()}
onChange={(value: any) => onChange(dateTime(value))}
allowEmpty={false}
showSecond={false}
value={dateTimeAsMoment(value)}
showHour={showHour}
minuteStep={minuteStep}
inputIcon={<Caret wrapperStyle={styles.caretWrapper} />}
/>
</div>
);
};
interface CaretProps {
wrapperStyle?: string;
}
const Caret: FC<CaretProps> = ({ wrapperStyle = '' }) => {
return (
<div className={wrapperStyle}>
<Icon name="angle-down" />
</div>
);
};

View File

@ -1,15 +1,15 @@
import React, { FC, FormEvent, MouseEvent, useState } from 'react'; import React, { FC, FormEvent, MouseEvent, useState } from 'react';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { dateMath, dateTime, getDefaultTimeRange, GrafanaTheme2, TimeRange, TimeZone } from '@grafana/data'; import { dateMath, dateTime, getDefaultTimeRange, GrafanaTheme2, TimeRange, TimeZone } from '@grafana/data';
import { useStyles2 } from '../../themes/ThemeContext'; import { useTheme2 } from '../../themes/ThemeContext';
import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper'; import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper';
import { Icon } from '../Icon/Icon'; import { Icon } from '../Icon/Icon';
import { getInputStyles } from '../Input/Input'; import { getInputStyles } from '../Input/Input';
import { getFocusStyle } from '../Forms/commonStyles';
import { TimePickerButtonLabel } from './TimeRangePicker'; import { TimePickerButtonLabel } from './TimeRangePicker';
import { TimePickerContent } from './TimeRangePicker/TimePickerContent'; import { TimePickerContent } from './TimeRangePicker/TimePickerContent';
import { otherOptions, quickOptions } from './rangeOptions'; import { otherOptions, quickOptions } from './rangeOptions';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { stylesFactory } from '../../themes';
const isValidTimeRange = (range: any) => { const isValidTimeRange = (range: any) => {
return dateMath.isValid(range.from) && dateMath.isValid(range.to); return dateMath.isValid(range.from) && dateMath.isValid(range.to);
@ -25,6 +25,7 @@ export interface TimeRangeInputProps {
clearable?: boolean; clearable?: boolean;
isReversed?: boolean; isReversed?: boolean;
hideQuickRanges?: boolean; hideQuickRanges?: boolean;
disabled?: boolean;
} }
const noop = () => {}; const noop = () => {};
@ -39,13 +40,18 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
placeholder = 'Select time range', placeholder = 'Select time range',
isReversed = true, isReversed = true,
hideQuickRanges = false, hideQuickRanges = false,
disabled = false,
}) => { }) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const styles = useStyles2(getStyles); const theme = useTheme2();
const styles = getStyles(theme, disabled);
const onOpen = (event: FormEvent<HTMLDivElement>) => { const onOpen = (event: FormEvent<HTMLDivElement>) => {
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
if (disabled) {
return;
}
setIsOpen(!isOpen); setIsOpen(!isOpen);
}; };
@ -79,12 +85,14 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
<span className={styles.placeholder}>{placeholder}</span> <span className={styles.placeholder}>{placeholder}</span>
)} )}
{!disabled && (
<span className={styles.caretIcon}> <span className={styles.caretIcon}>
{isValidTimeRange(value) && clearable && ( {isValidTimeRange(value) && clearable && (
<Icon className={styles.clearIcon} name="times" size="lg" onClick={onRangeClear} /> <Icon className={styles.clearIcon} name="times" size="lg" onClick={onRangeClear} />
)} )}
<Icon name={isOpen ? 'angle-up' : 'angle-down'} size="lg" /> <Icon name={isOpen ? 'angle-up' : 'angle-down'} size="lg" />
</span> </span>
)}
</div> </div>
{isOpen && ( {isOpen && (
<ClickOutsideWrapper includeButtonPress={false} onClick={onClose}> <ClickOutsideWrapper includeButtonPress={false} onClick={onClose}>
@ -106,7 +114,7 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
); );
}; };
const getStyles = (theme: GrafanaTheme2) => { const getStyles = stylesFactory((theme: GrafanaTheme2, disabled = false) => {
const inputStyles = getInputStyles({ theme, invalid: false }); const inputStyles = getInputStyles({ theme, invalid: false });
return { return {
container: css` container: css`
@ -118,6 +126,7 @@ const getStyles = (theme: GrafanaTheme2) => {
`, `,
pickerInput: cx( pickerInput: cx(
inputStyles.input, inputStyles.input,
disabled && inputStyles.inputDisabled,
inputStyles.wrapper, inputStyles.wrapper,
css` css`
display: flex; display: flex;
@ -126,7 +135,6 @@ const getStyles = (theme: GrafanaTheme2) => {
cursor: pointer; cursor: pointer;
padding-right: 0; padding-right: 0;
line-height: ${theme.v1.spacing.formInputHeight - 2}px; line-height: ${theme.v1.spacing.formInputHeight - 2}px;
${getFocusStyle(theme.v1)};
` `
), ),
caretIcon: cx( caretIcon: cx(
@ -147,4 +155,4 @@ const getStyles = (theme: GrafanaTheme2) => {
opacity: 1; opacity: 1;
`, `,
}; };
}; });

View File

@ -21,10 +21,11 @@ export interface Props {
autoFocus?: boolean; autoFocus?: boolean;
onBlur?: () => void; onBlur?: () => void;
includeInternal?: boolean; includeInternal?: boolean;
disabled?: boolean;
} }
export const TimeZonePicker: React.FC<Props> = (props) => { export const TimeZonePicker: React.FC<Props> = (props) => {
const { onChange, width, autoFocus = false, onBlur, value, includeInternal = false } = props; const { onChange, width, autoFocus = false, onBlur, value, includeInternal = false, disabled = false } = props;
const groupedTimeZones = useTimeZones(includeInternal); const groupedTimeZones = useTimeZones(includeInternal);
const selected = useSelectedTimeZone(groupedTimeZones, value); const selected = useSelectedTimeZone(groupedTimeZones, value);
const filterBySearchIndex = useFilterBySearchIndex(); const filterBySearchIndex = useFilterBySearchIndex();
@ -52,6 +53,7 @@ export const TimeZonePicker: React.FC<Props> = (props) => {
onChange={onChangeTz} onChange={onChangeTz}
onBlur={onBlur} onBlur={onBlur}
components={{ Option: TimeZoneOption, Group: TimeZoneGroup }} components={{ Option: TimeZoneOption, Group: TimeZoneGroup }}
disabled={disabled}
/> />
); );
}; };