From 33050f700ee12f3d4c580edde427aa47f734922f Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Sun, 22 Sep 2024 15:24:54 +1000 Subject: [PATCH] Prevent mouse wheel window scrolling on other number fields (#5283) --- .../Filters/HierarchicalLabelValueFilter.tsx | 4 ++-- .../components/List/Filters/NumberFilter.tsx | 10 ++++------ .../components/List/Filters/PhashFilter.tsx | 4 ++-- .../List/Filters/SelectableFilter.tsx | 4 ++-- ui/v2.5/src/components/List/ListFilter.tsx | 4 ++++ ui/v2.5/src/components/List/Pagination.tsx | 4 ++++ .../Scenes/SceneDetails/SceneGroupTable.tsx | 4 ++-- .../Settings/GeneratePreviewOptions.tsx | 7 +++---- ui/v2.5/src/components/Settings/Inputs.tsx | 4 ++-- .../components/Shared/Rating/RatingNumber.tsx | 2 ++ ui/v2.5/src/utils/form.tsx | 19 +++++++++++++++---- 11 files changed, 42 insertions(+), 24 deletions(-) diff --git a/ui/v2.5/src/components/List/Filters/HierarchicalLabelValueFilter.tsx b/ui/v2.5/src/components/List/Filters/HierarchicalLabelValueFilter.tsx index 71ff92e5e..8d96a8a8d 100644 --- a/ui/v2.5/src/components/List/Filters/HierarchicalLabelValueFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/HierarchicalLabelValueFilter.tsx @@ -4,6 +4,7 @@ import { defineMessages, MessageDescriptor, useIntl } from "react-intl"; import { FilterSelect, SelectObject } from "src/components/Shared/Select"; import { Criterion } from "src/models/list-filter/criteria/criterion"; import { IHierarchicalLabelValue } from "src/models/list-filter/types"; +import { NumberField } from "src/utils/form"; interface IHierarchicalLabelValueFilterProps { criterion: Criterion; @@ -104,9 +105,8 @@ export const HierarchicalLabelValueFilter: React.FC< {criterion.value.depth !== 0 && ( - onDepthChanged(e.target.value ? parseInt(e.target.value, 10) : -1) diff --git a/ui/v2.5/src/components/List/Filters/NumberFilter.tsx b/ui/v2.5/src/components/List/Filters/NumberFilter.tsx index 7aa574a2e..21120f799 100644 --- a/ui/v2.5/src/components/List/Filters/NumberFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/NumberFilter.tsx @@ -4,6 +4,7 @@ import { useIntl } from "react-intl"; import { CriterionModifier } from "../../../core/generated-graphql"; import { INumberValue } from "../../../models/list-filter/types"; import { NumberCriterion } from "../../../models/list-filter/criteria/criterion"; +import { NumberField } from "src/utils/form"; interface IDurationFilterProps { criterion: NumberCriterion; @@ -36,9 +37,8 @@ export const NumberFilter: React.FC = ({ ) { equalsControl = ( - ) => onChanged(e, "value") } @@ -57,9 +57,8 @@ export const NumberFilter: React.FC = ({ ) { lowerControl = ( - ) => onChanged(e, "value") } @@ -78,9 +77,8 @@ export const NumberFilter: React.FC = ({ ) { upperControl = ( - ) => onChanged( e, diff --git a/ui/v2.5/src/components/List/Filters/PhashFilter.tsx b/ui/v2.5/src/components/List/Filters/PhashFilter.tsx index 68eda8002..a42a61287 100644 --- a/ui/v2.5/src/components/List/Filters/PhashFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/PhashFilter.tsx @@ -4,6 +4,7 @@ import { useIntl } from "react-intl"; import { IPhashDistanceValue } from "../../../models/list-filter/types"; import { Criterion } from "../../../models/list-filter/criteria/criterion"; import { CriterionModifier } from "src/core/generated-graphql"; +import { NumberField } from "src/utils/form"; interface IPhashFilterProps { criterion: Criterion; @@ -49,10 +50,9 @@ export const PhashFilter: React.FC = ({ {criterion.modifier !== CriterionModifier.IsNull && criterion.modifier !== CriterionModifier.NotNull && ( - diff --git a/ui/v2.5/src/components/List/Filters/SelectableFilter.tsx b/ui/v2.5/src/components/List/Filters/SelectableFilter.tsx index 19d2b70bb..e6f8f9fcf 100644 --- a/ui/v2.5/src/components/List/Filters/SelectableFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/SelectableFilter.tsx @@ -25,6 +25,7 @@ import { keyboardClickHandler } from "src/utils/keyboard"; import { useDebounce } from "src/hooks/debounce"; import useFocus from "src/utils/focus"; import ScreenUtils from "src/utils/screen"; +import { NumberField } from "src/utils/form"; interface ISelectedItem { item: ILabeledId; @@ -361,9 +362,8 @@ export const HierarchicalObjectsFilter = < {criterion.value.depth !== 0 && ( - onDepthChanged(e.target.value ? parseInt(e.target.value, 10) : -1) diff --git a/ui/v2.5/src/components/List/ListFilter.tsx b/ui/v2.5/src/components/List/ListFilter.tsx index 24ea02af1..109ac127a 100644 --- a/ui/v2.5/src/components/List/ListFilter.tsx +++ b/ui/v2.5/src/components/List/ListFilter.tsx @@ -35,6 +35,7 @@ import { FilterButton } from "./Filters/FilterButton"; import { useDebounce } from "src/hooks/debounce"; import { View } from "./views"; import { ClearableInput } from "../Shared/ClearableInput"; +import { useStopWheelScroll } from "src/utils/form"; export function useDebouncedSearchInput( filter: ListFilterModel, @@ -126,6 +127,8 @@ export const PageSizeSelector: React.FC<{ } }, [customPageSizeShowing, perPageFocus]); + useStopWheelScroll(perPageInput); + const pageSizeOptions = useMemo(() => { const ret = PAGE_SIZE_OPTIONS.map((o) => { return { @@ -190,6 +193,7 @@ export const PageSizeSelector: React.FC<{
+ {/* can't use NumberField because of the ref */} { const maxPagesToShow = 10; const min = Math.max(1, currentPage - maxPagesToShow / 2); @@ -98,6 +101,7 @@ const PageCount: React.FC<{ + {/* can't use NumberField because of the ref */} ; @@ -92,9 +93,8 @@ export const SceneGroupTable: React.FC = (props) => { /> - ) => { updateFieldChanged( diff --git a/ui/v2.5/src/components/Settings/GeneratePreviewOptions.tsx b/ui/v2.5/src/components/Settings/GeneratePreviewOptions.tsx index bb4cba77d..c7987add6 100644 --- a/ui/v2.5/src/components/Settings/GeneratePreviewOptions.tsx +++ b/ui/v2.5/src/components/Settings/GeneratePreviewOptions.tsx @@ -2,6 +2,7 @@ import React from "react"; import { useIntl } from "react-intl"; import { Form } from "react-bootstrap"; import * as GQL from "src/core/generated-graphql"; +import { NumberField } from "src/utils/form"; export type VideoPreviewSettingsInput = Pick< GQL.ConfigGeneralInput, @@ -44,9 +45,8 @@ export const VideoPreviewInput: React.FC = ({ id: "dialogs.scene_gen.preview_seg_count_head", })} - ) => @@ -71,9 +71,8 @@ export const VideoPreviewInput: React.FC = ({ id: "dialogs.scene_gen.preview_seg_duration_head", })} - ) => set({ diff --git a/ui/v2.5/src/components/Settings/Inputs.tsx b/ui/v2.5/src/components/Settings/Inputs.tsx index 073be4e11..b84232d1f 100644 --- a/ui/v2.5/src/components/Settings/Inputs.tsx +++ b/ui/v2.5/src/components/Settings/Inputs.tsx @@ -6,6 +6,7 @@ import { Icon } from "../Shared/Icon"; import { StringListInput } from "../Shared/StringListInput"; import { PatchComponent } from "src/patch"; import { useSettings, useSettingsOptional } from "./context"; +import { NumberField } from "src/utils/form"; interface ISetting { id?: string; @@ -484,9 +485,8 @@ export const NumberSetting: React.FC = PatchComponent( {...props} renderField={(value, setValue) => ( - ) => setValue(Number.parseInt(e.currentTarget.value || "0", 10)) diff --git a/ui/v2.5/src/components/Shared/Rating/RatingNumber.tsx b/ui/v2.5/src/components/Shared/Rating/RatingNumber.tsx index 14cd701d1..69195ff40 100644 --- a/ui/v2.5/src/components/Shared/Rating/RatingNumber.tsx +++ b/ui/v2.5/src/components/Shared/Rating/RatingNumber.tsx @@ -3,6 +3,7 @@ import { Button } from "react-bootstrap"; import { Icon } from "../Icon"; import { faPencil, faStar } from "@fortawesome/free-solid-svg-icons"; import { useFocusOnce } from "src/utils/focus"; +import { useStopWheelScroll } from "src/utils/form"; export interface IRatingNumberProps { value: number | null; @@ -26,6 +27,7 @@ export const RatingNumber: React.FC = ( const showTextField = !props.disabled && (editing || !props.clickToRate); const [ratingRef] = useFocusOnce(editing, true); + useStopWheelScroll(ratingRef); const effectiveValue = editing ? valueStage : props.value; diff --git a/ui/v2.5/src/utils/form.tsx b/ui/v2.5/src/utils/form.tsx index 40fedc7bf..45b0aa86f 100644 --- a/ui/v2.5/src/utils/form.tsx +++ b/ui/v2.5/src/utils/form.tsx @@ -48,6 +48,7 @@ export function renderLabel(options: { // the mouse wheel will change the field value _and_ scroll the window. // This hook prevents the propagation that causes the window to scroll. export function useStopWheelScroll(ref: React.RefObject) { + // removed the dependency array because the underlying ref value may change useEffect(() => { const { current } = ref; @@ -66,17 +67,18 @@ export function useStopWheelScroll(ref: React.RefObject) { current.removeEventListener("wheel", stopWheelScroll); } }; - }, [ref]); + }); } -const InputField: React.FC< +// NumberField is a wrapper around Form.Control that prevents wheel events from scrolling the window. +export const NumberField: React.FC< InputHTMLAttributes & FormControlProps > = (props) => { const inputRef = useRef(null); useStopWheelScroll(inputRef); - return ; + return ; }; type Formik = ReturnType>; @@ -134,9 +136,18 @@ export function formikUtils( isInvalid={!!error} /> ); + } else if (type === "number") { + ; } else { control = ( -