Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent mouse wheel window scrolling on other number fields #5283

Merged
merged 1 commit into from
Sep 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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<IHierarchicalLabelValue>;
Expand Down Expand Up @@ -104,9 +105,8 @@ export const HierarchicalLabelValueFilter: React.FC<

{criterion.value.depth !== 0 && (
<Form.Group>
<Form.Control
<NumberField
className="btn-secondary"
type="number"
placeholder={intl.formatMessage(messages.studio_depth)}
onChange={(e) =>
onDepthChanged(e.target.value ? parseInt(e.target.value, 10) : -1)
Expand Down
10 changes: 4 additions & 6 deletions ui/v2.5/src/components/List/Filters/NumberFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -36,9 +37,8 @@ export const NumberFilter: React.FC<IDurationFilterProps> = ({
) {
equalsControl = (
<Form.Group>
<Form.Control
<NumberField
className="btn-secondary"
type="number"
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
onChanged(e, "value")
}
Expand All @@ -57,9 +57,8 @@ export const NumberFilter: React.FC<IDurationFilterProps> = ({
) {
lowerControl = (
<Form.Group>
<Form.Control
<NumberField
className="btn-secondary"
type="number"
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
onChanged(e, "value")
}
Expand All @@ -78,9 +77,8 @@ export const NumberFilter: React.FC<IDurationFilterProps> = ({
) {
upperControl = (
<Form.Group>
<Form.Control
<NumberField
className="btn-secondary"
type="number"
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
onChanged(
e,
Expand Down
4 changes: 2 additions & 2 deletions ui/v2.5/src/components/List/Filters/PhashFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<IPhashDistanceValue>;
Expand Down Expand Up @@ -49,10 +50,9 @@ export const PhashFilter: React.FC<IPhashFilterProps> = ({
{criterion.modifier !== CriterionModifier.IsNull &&
criterion.modifier !== CriterionModifier.NotNull && (
<Form.Group>
<Form.Control
<NumberField
className="btn-secondary"
onChange={distanceChanged}
type="number"
value={value ? value.distance : ""}
placeholder={intl.formatMessage({ id: "distance" })}
/>
Expand Down
4 changes: 2 additions & 2 deletions ui/v2.5/src/components/List/Filters/SelectableFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -361,9 +362,8 @@ export const HierarchicalObjectsFilter = <

{criterion.value.depth !== 0 && (
<Form.Group>
<Form.Control
<NumberField
className="btn-secondary"
type="number"
placeholder={intl.formatMessage(messages.studio_depth)}
onChange={(e) =>
onDepthChanged(e.target.value ? parseInt(e.target.value, 10) : -1)
Expand Down
4 changes: 4 additions & 0 deletions ui/v2.5/src/components/List/ListFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -126,6 +127,8 @@ export const PageSizeSelector: React.FC<{
}
}, [customPageSizeShowing, perPageFocus]);

useStopWheelScroll(perPageInput);

const pageSizeOptions = useMemo(() => {
const ret = PAGE_SIZE_OPTIONS.map((o) => {
return {
Expand Down Expand Up @@ -190,6 +193,7 @@ export const PageSizeSelector: React.FC<{
<Popover id="custom_pagesize_popover">
<Form inline>
<InputGroup>
{/* can't use NumberField because of the ref */}
<Form.Control
type="number"
min={1}
Expand Down
4 changes: 4 additions & 0 deletions ui/v2.5/src/components/List/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
import useFocus from "src/utils/focus";
import { Icon } from "../Shared/Icon";
import { faCheck, faChevronDown } from "@fortawesome/free-solid-svg-icons";
import { useStopWheelScroll } from "src/utils/form";

const PageCount: React.FC<{
totalPages: number;
Expand All @@ -32,6 +33,8 @@ const PageCount: React.FC<{
}
}, [showSelectPage, pageFocus]);

useStopWheelScroll(pageInput);

const pageOptions = useMemo(() => {
const maxPagesToShow = 10;
const min = Math.max(1, currentPage - maxPagesToShow / 2);
Expand Down Expand Up @@ -98,6 +101,7 @@ const PageCount: React.FC<{
<Popover id="select_page_popover">
<Form inline>
<InputGroup>
{/* can't use NumberField because of the ref */}
<Form.Control
type="number"
min={1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as GQL from "src/core/generated-graphql";
import { Form, Row, Col } from "react-bootstrap";
import { Group, GroupSelect } from "src/components/Groups/GroupSelect";
import cx from "classnames";
import { NumberField } from "src/utils/form";

export type GroupSceneIndexMap = Map<string, number | undefined>;

Expand Down Expand Up @@ -92,9 +93,8 @@ export const SceneGroupTable: React.FC<IProps> = (props) => {
/>
</Col>
<Col xs={3}>
<Form.Control
<NumberField
className="text-input"
type="number"
value={m.scene_index ?? ""}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateFieldChanged(
Expand Down
7 changes: 3 additions & 4 deletions ui/v2.5/src/components/Settings/GeneratePreviewOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -44,9 +45,8 @@ export const VideoPreviewInput: React.FC<IVideoPreviewInput> = ({
id: "dialogs.scene_gen.preview_seg_count_head",
})}
</h6>
<Form.Control
<NumberField
className="text-input"
type="number"
value={previewSegments?.toString() ?? 1}
min={1}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
Expand All @@ -71,9 +71,8 @@ export const VideoPreviewInput: React.FC<IVideoPreviewInput> = ({
id: "dialogs.scene_gen.preview_seg_duration_head",
})}
</h6>
<Form.Control
<NumberField
className="text-input"
type="number"
value={previewSegmentDuration?.toString() ?? 0}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
set({
Expand Down
4 changes: 2 additions & 2 deletions ui/v2.5/src/components/Settings/Inputs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -484,9 +485,8 @@ export const NumberSetting: React.FC<INumberSetting> = PatchComponent(
<ModalSetting<number>
{...props}
renderField={(value, setValue) => (
<Form.Control
<NumberField
className="text-input"
type="number"
value={value ?? 0}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setValue(Number.parseInt(e.currentTarget.value || "0", 10))
Expand Down
2 changes: 2 additions & 0 deletions ui/v2.5/src/components/Shared/Rating/RatingNumber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,6 +27,7 @@ export const RatingNumber: React.FC<IRatingNumberProps> = (
const showTextField = !props.disabled && (editing || !props.clickToRate);

const [ratingRef] = useFocusOnce(editing, true);
useStopWheelScroll(ratingRef);

const effectiveValue = editing ? valueStage : props.value;

Expand Down
19 changes: 15 additions & 4 deletions ui/v2.5/src/utils/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLElement>) {
// removed the dependency array because the underlying ref value may change
useEffect(() => {
const { current } = ref;

Expand All @@ -66,17 +67,18 @@ export function useStopWheelScroll(ref: React.RefObject<HTMLElement>) {
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<HTMLInputElement> & FormControlProps
> = (props) => {
const inputRef = useRef<HTMLInputElement>(null);

useStopWheelScroll(inputRef);

return <Form.Control {...props} ref={inputRef} />;
return <Form.Control {...props} type="number" ref={inputRef} />;
};

type Formik<V extends FormikValues> = ReturnType<typeof useFormik<V>>;
Expand Down Expand Up @@ -134,9 +136,18 @@ export function formikUtils<V extends FormikValues>(
isInvalid={!!error}
/>
);
} else if (type === "number") {
<NumberField
type={type}
className="text-input"
placeholder={placeholder}
{...formikProps}
value={value}
isInvalid={!!error}
/>;
} else {
control = (
<InputField
<Form.Control
type={type}
className="text-input"
placeholder={placeholder}
Expand Down
Loading