diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx index 83f036576..eb9ace7e9 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx @@ -35,11 +35,8 @@ import Loading from 'src/components/Loading'; import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; import { waitForAsyncData } from 'src/middleware/asyncEvent'; -import { - setFocusedNativeFilter, - unsetFocusedNativeFilter, -} from 'src/dashboard/actions/nativeFilters'; import { ClientErrorObject } from 'src/utils/getClientErrorObject'; +import { dispatchFocusAction } from './utils'; import { FilterProps } from './types'; import { getFormData } from '../../utils'; import { useCascadingFilters } from './state'; @@ -184,8 +181,8 @@ const FilterValue: React.FC = ({ const setDataMask = (dataMask: DataMask) => onFilterSelectionChange(filter, dataMask); - const setFocusedFilter = () => dispatch(setFocusedNativeFilter(id)); - const unsetFocusedFilter = () => dispatch(unsetFocusedNativeFilter()); + const setFocusedFilter = () => dispatchFocusAction(dispatch, id); + const unsetFocusedFilter = () => dispatchFocusAction(dispatch); if (error) { return ( diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/utils.ts index 19b50ddf6..0b6d9a78f 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/utils.ts @@ -16,6 +16,12 @@ * specific language governing permissions and limitations * under the License. */ +import { debounce } from 'lodash'; +import { Dispatch } from 'react'; +import { + setFocusedNativeFilter, + unsetFocusedNativeFilter, +} from 'src/dashboard/actions/nativeFilters'; import { Filter } from '../../types'; import { CascadeFilter } from '../CascadeFilters/types'; import { mapParentFiltersToChildren } from '../utils'; @@ -36,3 +42,14 @@ export function buildCascadeFiltersTree(filters: Filter[]): CascadeFilter[] { .filter(filter => !filter.cascadeParentIds?.length) .map(getCascadeFilter); } + +export const dispatchFocusAction = debounce( + (dispatch: Dispatch, id?: string) => { + if (id) { + dispatch(setFocusedNativeFilter(id)); + } else { + dispatch(unsetFocusedNativeFilter()); + } + }, + 300, +); diff --git a/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx index d6b3b2561..462fc4a29 100644 --- a/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx @@ -31,41 +31,47 @@ import { StatusMessage, StyledFormItem, Styles } from '../common'; import { getRangeExtraFormData } from '../../utils'; const Wrapper = styled.div<{ validateStatus?: 'error' | 'warning' | 'info' }>` - border: 1px solid transparent; - &:focus { - border: 1px solid - ${({ theme, validateStatus }) => - theme.colors[validateStatus || 'primary']?.base}; - outline: 0; - box-shadow: 0 0 0 3px - ${({ theme, validateStatus }) => - rgba(theme.colors[validateStatus || 'primary']?.base, 0.2)}; - } - & .ant-slider { - & .ant-slider-track { - background-color: ${({ theme, validateStatus }) => - validateStatus && theme.colors[validateStatus]?.light1}; + ${({ theme, validateStatus }) => ` + border: 1px solid transparent; + &:focus { + border: 1px solid + ${theme.colors[validateStatus || 'primary']?.base}; + outline: 0; + box-shadow: 0 0 0 3px + ${rgba(theme.colors[validateStatus || 'primary']?.base, 0.2)}; } - & .ant-slider-handle { - border: ${({ theme, validateStatus }) => - validateStatus && `2px solid ${theme.colors[validateStatus]?.light1}`}; - &:focus { - box-shadow: 0 0 0 3px - ${({ theme, validateStatus }) => - rgba(theme.colors[validateStatus || 'primary']?.base, 0.2)}; - } - } - &:hover { + & .ant-slider { + margin-top: ${theme.gridUnit}px; + margin-bottom: ${theme.gridUnit * 5}px; + & .ant-slider-track { - background-color: ${({ theme, validateStatus }) => - validateStatus && theme.colors[validateStatus]?.base}; + background-color: ${ + validateStatus && theme.colors[validateStatus]?.light1 + }; } & .ant-slider-handle { - border: ${({ theme, validateStatus }) => - validateStatus && `2px solid ${theme.colors[validateStatus]?.base}`}; + border: ${ + validateStatus && `2px solid ${theme.colors[validateStatus]?.light1}` + }; + &:focus { + box-shadow: 0 0 0 3px + ${rgba(theme.colors[validateStatus || 'primary']?.base, 0.2)}; + } + } + &:hover { + & .ant-slider-track { + background-color: ${ + validateStatus && theme.colors[validateStatus]?.base + }; + } + & .ant-slider-handle { + border: ${ + validateStatus && `2px solid ${theme.colors[validateStatus]?.base}` + }; + } } } - } + `} `; export default function RangeFilterPlugin(props: PluginFilterRangeProps) { diff --git a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx index 6c5b9a1cf..cac3da8f5 100644 --- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx @@ -308,7 +308,8 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { } return originNode; }} - onFocus={setFocusedFilter} + onMouseEnter={setFocusedFilter} + onMouseLeave={unsetFocusedFilter} // @ts-ignore onChange={handleChange} ref={inputRef} diff --git a/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx b/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx index d49e756a5..62127da1b 100644 --- a/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx @@ -103,8 +103,8 @@ export default function PluginFilterTimeColumn( placeholder={placeholderText} // @ts-ignore onChange={handleChange} - onBlur={unsetFocusedFilter} - onFocus={setFocusedFilter} + onMouseEnter={setFocusedFilter} + onMouseLeave={unsetFocusedFilter} ref={inputRef} > {timeColumns.map( diff --git a/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx b/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx index 5db92c3c3..22442be3a 100644 --- a/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx @@ -113,8 +113,8 @@ export default function PluginFilterTimegrain( placeholder={placeholderText} // @ts-ignore onChange={handleChange} - onBlur={unsetFocusedFilter} - onFocus={setFocusedFilter} + onMouseEnter={setFocusedFilter} + onMouseLeave={unsetFocusedFilter} ref={inputRef} > {(data || []).map((row: { name: string; duration: string }) => {