mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
6200c40160
commit
167bad070b
@ -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;
|
||||||
|
@ -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}
|
||||||
|
@ -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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@ -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;
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
};
|
});
|
||||||
|
@ -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}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user