Fix desktop long press action
After the long press action, the set onClick action was triggered as well. This caused issues like opening the manga page in the source browse page when adding the manga via a long press to the library
This commit is contained in:
196
.oxlintrc.jsonc
196
.oxlintrc.jsonc
@@ -1,20 +1,14 @@
|
|||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": ["react", "unicorn", "typescript", "import", "jsx-a11y"],
|
||||||
"react",
|
|
||||||
"unicorn",
|
|
||||||
"typescript",
|
|
||||||
"import",
|
|
||||||
"jsx-a11y"
|
|
||||||
],
|
|
||||||
"jsPlugins": [
|
"jsPlugins": [
|
||||||
"eslint-plugin-lingui",
|
"eslint-plugin-lingui",
|
||||||
"eslint-plugin-no-relative-import-paths",
|
"eslint-plugin-no-relative-import-paths",
|
||||||
"eslint-plugin-unused-imports",
|
"eslint-plugin-unused-imports",
|
||||||
"eslint-plugin-no-only-tests",
|
"eslint-plugin-no-only-tests",
|
||||||
"@tony.ganchev/eslint-plugin-header"
|
"@tony.ganchev/eslint-plugin-header",
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"correctness": "off"
|
"correctness": "off",
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
// ── Core JS: correctness (from js.configs.recommended) ──
|
// ── Core JS: correctness (from js.configs.recommended) ──
|
||||||
@@ -59,8 +53,8 @@
|
|||||||
"ignoreRestSiblings": true,
|
"ignoreRestSiblings": true,
|
||||||
"argsIgnorePattern": "^_",
|
"argsIgnorePattern": "^_",
|
||||||
"varsIgnorePattern": "^_",
|
"varsIgnorePattern": "^_",
|
||||||
"caughtErrorsIgnorePattern": "^_|^e$|^error$"
|
"caughtErrorsIgnorePattern": "^_|^e$|^error$",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"no-useless-backreference": "error",
|
"no-useless-backreference": "error",
|
||||||
"no-useless-catch": "error",
|
"no-useless-catch": "error",
|
||||||
@@ -76,21 +70,18 @@
|
|||||||
"no-else-return": [
|
"no-else-return": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"allowElseIf": false
|
"allowElseIf": false,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"no-lonely-if": "error",
|
"no-lonely-if": "error",
|
||||||
"no-unneeded-ternary": [
|
"no-unneeded-ternary": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"defaultAssignment": false
|
"defaultAssignment": false,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"no-multi-assign": "error",
|
"no-multi-assign": "error",
|
||||||
"no-return-assign": [
|
"no-return-assign": ["error", "always"],
|
||||||
"error",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"no-sequences": "error",
|
"no-sequences": "error",
|
||||||
"no-new": "error",
|
"no-new": "error",
|
||||||
"no-new-func": "error",
|
"no-new-func": "error",
|
||||||
@@ -100,11 +91,7 @@
|
|||||||
"no-self-compare": "error",
|
"no-self-compare": "error",
|
||||||
"no-extend-native": "error",
|
"no-extend-native": "error",
|
||||||
"no-alert": "error",
|
"no-alert": "error",
|
||||||
"no-restricted-globals": [
|
"no-restricted-globals": ["error", "isFinite", "isNaN"],
|
||||||
"error",
|
|
||||||
"isFinite",
|
|
||||||
"isNaN"
|
|
||||||
],
|
|
||||||
"no-await-in-loop": "error",
|
"no-await-in-loop": "error",
|
||||||
"no-promise-executor-return": "error",
|
"no-promise-executor-return": "error",
|
||||||
"no-template-curly-in-string": "error",
|
"no-template-curly-in-string": "error",
|
||||||
@@ -117,14 +104,14 @@
|
|||||||
"error",
|
"error",
|
||||||
"always",
|
"always",
|
||||||
{
|
{
|
||||||
"null": "ignore"
|
"null": "ignore",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"default-case": [
|
"default-case": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"commentPattern": "^no default$"
|
"commentPattern": "^no default$",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"default-case-last": "error",
|
"default-case-last": "error",
|
||||||
"yoda": "error",
|
"yoda": "error",
|
||||||
@@ -137,45 +124,39 @@
|
|||||||
"prefer-promise-reject-errors": [
|
"prefer-promise-reject-errors": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"allowEmptyReject": true
|
"allowEmptyReject": true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"no-param-reassign": [
|
"no-param-reassign": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"props": true,
|
"props": true,
|
||||||
"ignorePropertyModificationsForRegex": [
|
"ignorePropertyModificationsForRegex": ["^draft"],
|
||||||
"^draft"
|
},
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"no-restricted-imports": [
|
"no-restricted-imports": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
"group": [
|
"group": ["@mui/*", "!@mui/material/", "!@mui/icons-material/", "!@mui/x-date-pickers/"],
|
||||||
"@mui/*",
|
|
||||||
"!@mui/material/",
|
|
||||||
"!@mui/icons-material/",
|
|
||||||
"!@mui/x-date-pickers/"
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"group": [
|
"group": ["@mui/*/*/*"],
|
||||||
"@mui/*/*/*"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"group": [
|
"group": ["lodash", "lodash/*", "!lodash/fp/*"],
|
||||||
"lodash",
|
"message": "Use lodash-fp instead.",
|
||||||
"lodash/*",
|
},
|
||||||
"!lodash/fp/*"
|
|
||||||
],
|
],
|
||||||
"message": "Use lodash-fp instead."
|
"paths": [
|
||||||
}
|
{
|
||||||
]
|
"name": "use-long-press",
|
||||||
}
|
"importNames": ["useLongPress"],
|
||||||
|
"message": "Use the wrapper \"usePress\" instead",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
// ── New: modern JS essentials ──
|
// ── New: modern JS essentials ──
|
||||||
@@ -185,10 +166,8 @@
|
|||||||
"no-warning-comments": [
|
"no-warning-comments": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"terms": [
|
"terms": ["@nocommit"],
|
||||||
"@nocommit"
|
},
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
|
|
||||||
// ── TypeScript rules (non-type-checked) ──
|
// ── TypeScript rules (non-type-checked) ──
|
||||||
@@ -199,8 +178,8 @@
|
|||||||
{
|
{
|
||||||
"functions": false,
|
"functions": false,
|
||||||
"classes": true,
|
"classes": true,
|
||||||
"variables": true
|
"variables": true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"default-param-last": "error",
|
"default-param-last": "error",
|
||||||
|
|
||||||
@@ -230,10 +209,7 @@
|
|||||||
"typescript/no-implied-eval": "error",
|
"typescript/no-implied-eval": "error",
|
||||||
"typescript/only-throw-error": "error",
|
"typescript/only-throw-error": "error",
|
||||||
"typescript/dot-notation": "error",
|
"typescript/dot-notation": "error",
|
||||||
"typescript/return-await": [
|
"typescript/return-await": ["error", "in-try-catch"],
|
||||||
"error",
|
|
||||||
"in-try-catch"
|
|
||||||
],
|
|
||||||
|
|
||||||
// ── Import rules ──
|
// ── Import rules ──
|
||||||
"import/namespace": "error",
|
"import/namespace": "error",
|
||||||
@@ -269,28 +245,22 @@
|
|||||||
"react/jsx-no-useless-fragment": "error",
|
"react/jsx-no-useless-fragment": "error",
|
||||||
"react/jsx-no-constructed-context-values": "error",
|
"react/jsx-no-constructed-context-values": "error",
|
||||||
"react/self-closing-comp": "error",
|
"react/self-closing-comp": "error",
|
||||||
"react/jsx-boolean-value": [
|
"react/jsx-boolean-value": ["error", "never"],
|
||||||
"error",
|
|
||||||
"never"
|
|
||||||
],
|
|
||||||
"react/jsx-pascal-case": [
|
"react/jsx-pascal-case": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"allowAllCaps": true
|
"allowAllCaps": true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"react/button-has-type": "error",
|
"react/button-has-type": "error",
|
||||||
"react/jsx-curly-brace-presence": [
|
"react/jsx-curly-brace-presence": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"props": "never",
|
"props": "never",
|
||||||
"children": "never"
|
"children": "never",
|
||||||
}
|
},
|
||||||
],
|
|
||||||
"react/jsx-fragments": [
|
|
||||||
"error",
|
|
||||||
"syntax"
|
|
||||||
],
|
],
|
||||||
|
"react/jsx-fragments": ["error", "syntax"],
|
||||||
"react/jsx-no-script-url": "error",
|
"react/jsx-no-script-url": "error",
|
||||||
"react/style-prop-object": "error",
|
"react/style-prop-object": "error",
|
||||||
"react/void-dom-elements-no-children": "error",
|
"react/void-dom-elements-no-children": "error",
|
||||||
@@ -318,34 +288,25 @@
|
|||||||
"jsx_a11y/no-autofocus": [
|
"jsx_a11y/no-autofocus": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"ignoreNonDOM": true
|
"ignoreNonDOM": true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"jsx_a11y/no-distracting-elements": "error",
|
"jsx_a11y/no-distracting-elements": "error",
|
||||||
"jsx_a11y/no-noninteractive-tabindex": [
|
"jsx_a11y/no-noninteractive-tabindex": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"tags": [],
|
"tags": [],
|
||||||
"roles": [
|
"roles": ["tabpanel"],
|
||||||
"tabpanel"
|
"allowExpressionValues": true,
|
||||||
],
|
},
|
||||||
"allowExpressionValues": true
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"jsx_a11y/no-redundant-roles": "error",
|
"jsx_a11y/no-redundant-roles": "error",
|
||||||
"jsx_a11y/no-static-element-interactions": [
|
"jsx_a11y/no-static-element-interactions": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"allowExpressionValues": true,
|
"allowExpressionValues": true,
|
||||||
"handlers": [
|
"handlers": ["onClick", "onMouseDown", "onMouseUp", "onKeyPress", "onKeyDown", "onKeyUp"],
|
||||||
"onClick",
|
},
|
||||||
"onMouseDown",
|
|
||||||
"onMouseUp",
|
|
||||||
"onKeyPress",
|
|
||||||
"onKeyDown",
|
|
||||||
"onKeyUp"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"jsx_a11y/role-has-required-aria-props": "error",
|
"jsx_a11y/role-has-required-aria-props": "error",
|
||||||
"jsx_a11y/role-supports-aria-props": "error",
|
"jsx_a11y/role-supports-aria-props": "error",
|
||||||
@@ -369,29 +330,34 @@
|
|||||||
"no-only-tests/no-only-tests": "error",
|
"no-only-tests/no-only-tests": "error",
|
||||||
|
|
||||||
// ── License header ──
|
// ── License header ──
|
||||||
"@tony.ganchev/header/header": ["error", "block", [
|
"@tony.ganchev/header/header": [
|
||||||
|
"error",
|
||||||
|
"block",
|
||||||
|
[
|
||||||
"",
|
"",
|
||||||
" * Copyright (C) Contributors to the Suwayomi project",
|
" * Copyright (C) Contributors to the Suwayomi project",
|
||||||
" *",
|
" *",
|
||||||
" * This Source Code Form is subject to the terms of the Mozilla Public",
|
" * This Source Code Form is subject to the terms of the Mozilla Public",
|
||||||
" * License, v. 2.0. If a copy of the MPL was not distributed with this",
|
" * License, v. 2.0. If a copy of the MPL was not distributed with this",
|
||||||
" * file, You can obtain one at https://mozilla.org/MPL/2.0/.",
|
" * file, You can obtain one at https://mozilla.org/MPL/2.0/.",
|
||||||
" "
|
" ",
|
||||||
], 2]
|
],
|
||||||
|
2,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"jsx-a11y": {
|
"jsx-a11y": {
|
||||||
"components": {},
|
"components": {},
|
||||||
"attributes": {}
|
"attributes": {},
|
||||||
},
|
},
|
||||||
"next": {
|
"next": {
|
||||||
"rootDir": []
|
"rootDir": [],
|
||||||
},
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"formComponents": [],
|
"formComponents": [],
|
||||||
"linkComponents": [],
|
"linkComponents": [],
|
||||||
"version": "19.2.0",
|
"version": "19.2.0",
|
||||||
"componentWrapperFunctions": []
|
"componentWrapperFunctions": [],
|
||||||
},
|
},
|
||||||
"jsdoc": {
|
"jsdoc": {
|
||||||
"ignorePrivate": false,
|
"ignorePrivate": false,
|
||||||
@@ -401,15 +367,15 @@
|
|||||||
"augmentsExtendsReplacesDocs": false,
|
"augmentsExtendsReplacesDocs": false,
|
||||||
"implementsReplacesDocs": false,
|
"implementsReplacesDocs": false,
|
||||||
"exemptDestructuredRootsFromChecks": false,
|
"exemptDestructuredRootsFromChecks": false,
|
||||||
"tagNamePreference": {}
|
"tagNamePreference": {},
|
||||||
},
|
},
|
||||||
"vitest": {
|
"vitest": {
|
||||||
"typecheck": false
|
"typecheck": false,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"builtin": true
|
"builtin": true,
|
||||||
},
|
},
|
||||||
"globals": {},
|
"globals": {},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
@@ -426,36 +392,28 @@
|
|||||||
"src/lib/dnd-kit/DndKitUtil.ts",
|
"src/lib/dnd-kit/DndKitUtil.ts",
|
||||||
"src/lib/requests/RequestManager.ts",
|
"src/lib/requests/RequestManager.ts",
|
||||||
"src/lib/requests/client/GraphQLClient.ts",
|
"src/lib/requests/client/GraphQLClient.ts",
|
||||||
"src/lib/virtuoso/Virtuoso.util.tsx"
|
"src/lib/virtuoso/Virtuoso.util.tsx",
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"react/rules-of-hooks": "off"
|
"react/rules-of-hooks": "off",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": [
|
"files": ["**/*.config.ts", "**/*.config.js"],
|
||||||
"**/*.config.ts",
|
|
||||||
"**/*.config.js"
|
|
||||||
],
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"import/no-default-export": "off"
|
"import/no-default-export": "off",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": [
|
"files": ["tools/scripts/**/*"],
|
||||||
"tools/scripts/**/*"
|
|
||||||
],
|
|
||||||
"env": {
|
"env": {
|
||||||
"node": true
|
"node": true,
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-console": "off",
|
"no-console": "off",
|
||||||
"no-relative-import-paths/no-relative-import-paths": "off"
|
"no-relative-import-paths/no-relative-import-paths": "off",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"ignorePatterns": [
|
"ignorePatterns": ["src/lib/graphql/generated/**", "tools/eslint-plugin-header.cjs"],
|
||||||
"src/lib/graphql/generated/**",
|
|
||||||
"tools/eslint-plugin-header.cjs"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- (**General**) Fix long press actions on desktop
|
||||||
- (**Migration**) Fix aborting bulk migration search/execution while webUI is served on a subpath
|
- (**Migration**) Fix aborting bulk migration search/execution while webUI is served on a subpath
|
||||||
- (**Migration**) Fix retry button never being shown for failed search/migration entries
|
- (**Migration**) Fix retry button never being shown for failed search/migration entries
|
||||||
- (**Migration**) Fix showing an empty "Available" source group header when all sources are selected
|
- (**Migration**) Fix showing an empty "Available" source group header when all sources are selected
|
||||||
|
|||||||
71
src/base/hooks/usePress.ts
Normal file
71
src/base/hooks/usePress.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useCallback, useRef } from 'react';
|
||||||
|
import type {
|
||||||
|
LongPressCallbackMeta,
|
||||||
|
LongPressMouseHandlers,
|
||||||
|
LongPressPointerHandlers,
|
||||||
|
LongPressReactEvents,
|
||||||
|
LongPressResult,
|
||||||
|
LongPressTouchHandlers,
|
||||||
|
} from 'use-long-press';
|
||||||
|
// oxlint-disable-next-line no-restricted-imports
|
||||||
|
import { useLongPress } from 'use-long-press';
|
||||||
|
|
||||||
|
export type UsePressResult = LongPressResult<
|
||||||
|
(LongPressPointerHandlers | LongPressMouseHandlers | LongPressTouchHandlers) & {
|
||||||
|
onClick: (event: React.MouseEvent | React.TouchEvent) => void;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const usePress = (
|
||||||
|
options: Omit<Parameters<typeof useLongPress>[1], 'onCancel' | 'onStart'> & {
|
||||||
|
onLongPress: NonNullable<Parameters<typeof useLongPress>[0]>;
|
||||||
|
onPress: (event: React.MouseEvent | React.TouchEvent) => void;
|
||||||
|
},
|
||||||
|
): UsePressResult => {
|
||||||
|
const { onLongPress, onPress, ...actualOptions } = options;
|
||||||
|
|
||||||
|
const hasLongPressRef = useRef(false);
|
||||||
|
|
||||||
|
const onCancel = useCallback(() => {
|
||||||
|
if (hasLongPressRef.current) {
|
||||||
|
hasLongPressRef.current = false;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const bind = useLongPress(
|
||||||
|
useCallback(
|
||||||
|
(event: LongPressReactEvents<Element>, meta: LongPressCallbackMeta<unknown>) => {
|
||||||
|
hasLongPressRef.current = true;
|
||||||
|
onLongPress(event, meta);
|
||||||
|
},
|
||||||
|
[onLongPress],
|
||||||
|
),
|
||||||
|
{
|
||||||
|
...actualOptions,
|
||||||
|
onCancel,
|
||||||
|
onStart: onCancel,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return useCallback(
|
||||||
|
(context?: unknown) => ({
|
||||||
|
...bind(context),
|
||||||
|
onClick: (event: React.MouseEvent | React.TouchEvent) => {
|
||||||
|
if (!hasLongPressRef.current) {
|
||||||
|
onPress(event);
|
||||||
|
} else {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[bind, onPress],
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -18,7 +18,6 @@ import type { MouseEvent, TouchEvent } from 'react';
|
|||||||
import React, { memo, useRef } from 'react';
|
import React, { memo, useRef } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
|
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
|
||||||
import { useLongPress } from 'use-long-press';
|
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { CustomTooltip } from '@/base/components/CustomTooltip.tsx';
|
import { CustomTooltip } from '@/base/components/CustomTooltip.tsx';
|
||||||
import { getDateString } from '@/base/utils/DateHelper.ts';
|
import { getDateString } from '@/base/utils/DateHelper.ts';
|
||||||
@@ -43,6 +42,7 @@ import type {
|
|||||||
} from '@/features/chapter/Chapter.types.ts';
|
} from '@/features/chapter/Chapter.types.ts';
|
||||||
import { MediaQuery } from '@/base/utils/MediaQuery.tsx';
|
import { MediaQuery } from '@/base/utils/MediaQuery.tsx';
|
||||||
import type { ChapterType } from '@/lib/graphql/generated/graphql-base.types.ts';
|
import type { ChapterType } from '@/lib/graphql/generated/graphql-base.types.ts';
|
||||||
|
import { usePress } from '@/base/hooks/usePress.ts';
|
||||||
|
|
||||||
type TChapter = ChapterIdInfo &
|
type TChapter = ChapterIdInfo &
|
||||||
ChapterMangaInfo &
|
ChapterMangaInfo &
|
||||||
@@ -104,7 +104,8 @@ export const ChapterCard = memo((props: IProps) => {
|
|||||||
onSelect(chapter.id, !selected, event.shiftKey);
|
onSelect(chapter.id, !selected, event.shiftKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
const longPressBind = useLongPress((event, { context: openMenu }) => {
|
const longPressBind = usePress({
|
||||||
|
onLongPress: (event, { context: openMenu }) => {
|
||||||
if (!isSelecting && !!menuButtonRef.current) {
|
if (!isSelecting && !!menuButtonRef.current) {
|
||||||
handleClickOpenMenu(event, () => (openMenu as (event: Element) => void)?.(menuButtonRef.current!));
|
handleClickOpenMenu(event, () => (openMenu as (event: Element) => void)?.(menuButtonRef.current!));
|
||||||
return;
|
return;
|
||||||
@@ -113,6 +114,8 @@ export const ChapterCard = memo((props: IProps) => {
|
|||||||
// oxlint-disable-next-line no-param-reassign
|
// oxlint-disable-next-line no-param-reassign
|
||||||
event.shiftKey = true;
|
event.shiftKey = true;
|
||||||
handleClick(event);
|
handleClick(event);
|
||||||
|
},
|
||||||
|
onPress: handleClick,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -136,7 +139,6 @@ export const ChapterCard = memo((props: IProps) => {
|
|||||||
}}
|
}}
|
||||||
state={Chapters.getReaderOpenChapterLocationState(chapter, true)}
|
state={Chapters.getReaderOpenChapterLocationState(chapter, true)}
|
||||||
replace={mode === 'reader'}
|
replace={mode === 'reader'}
|
||||||
onClick={(e) => handleClick(e)}
|
|
||||||
{...longPressBind(popupState.open)}
|
{...longPressBind(popupState.open)}
|
||||||
>
|
>
|
||||||
<ListCardContent>
|
<ListCardContent>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { LongPressPointerHandlers, LongPressResult } from 'use-long-press';
|
|
||||||
import type { PopupState } from 'material-ui-popup-state/hooks';
|
import type { PopupState } from 'material-ui-popup-state/hooks';
|
||||||
import type { JSX } from 'react';
|
import type { JSX } from 'react';
|
||||||
import type { SelectableCollectionReturnType } from '@/base/collection/hooks/useSelectableCollection.ts';
|
import type { SelectableCollectionReturnType } from '@/base/collection/hooks/useSelectableCollection.ts';
|
||||||
@@ -29,6 +28,7 @@ import type {
|
|||||||
SourceType,
|
SourceType,
|
||||||
TrackRecordType,
|
TrackRecordType,
|
||||||
} from '@/lib/graphql/generated/graphql-base.types.ts';
|
} from '@/lib/graphql/generated/graphql-base.types.ts';
|
||||||
|
import type { UsePressResult } from '@/base/hooks/usePress.ts';
|
||||||
|
|
||||||
export type MangaCardMode = 'default' | 'source' | 'migrate.select.bulk' | 'migrate.select.single' | 'duplicate';
|
export type MangaCardMode = 'default' | 'source' | 'migrate.select.bulk' | 'migrate.select.single' | 'duplicate';
|
||||||
|
|
||||||
@@ -75,9 +75,8 @@ export interface MangaCardProps {
|
|||||||
export type SpecificMangaCardProps = Omit<MangaCardProps, 'manga'> &
|
export type SpecificMangaCardProps = Omit<MangaCardProps, 'manga'> &
|
||||||
Pick<ReturnType<typeof useManageMangaLibraryState>, 'isInLibrary'> & {
|
Pick<ReturnType<typeof useManageMangaLibraryState>, 'isInLibrary'> & {
|
||||||
manga: MangaCardSpecificProps;
|
manga: MangaCardSpecificProps;
|
||||||
longPressBind: LongPressResult<LongPressPointerHandlers>;
|
longPressBind: UsePressResult;
|
||||||
popupState: PopupState;
|
popupState: PopupState;
|
||||||
handleClick: (event: React.MouseEvent | React.TouchEvent) => void;
|
|
||||||
mangaLinkTo: string;
|
mangaLinkTo: string;
|
||||||
continueReadingButton: JSX.Element;
|
continueReadingButton: JSX.Element;
|
||||||
mangaBadges: JSX.Element;
|
mangaBadges: JSX.Element;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import PopupState, { bindMenu } from 'material-ui-popup-state';
|
import PopupState, { bindMenu } from 'material-ui-popup-state';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useLongPress } from 'use-long-press';
|
|
||||||
import type { SingleModeProps } from '@/features/manga/components/MangaActionMenuItems.tsx';
|
import type { SingleModeProps } from '@/features/manga/components/MangaActionMenuItems.tsx';
|
||||||
import { MangaActionMenuItems } from '@/features/manga/components/MangaActionMenuItems.tsx';
|
import { MangaActionMenuItems } from '@/features/manga/components/MangaActionMenuItems.tsx';
|
||||||
import { Menu } from '@/base/components/menu/Menu.tsx';
|
import { Menu } from '@/base/components/menu/Menu.tsx';
|
||||||
@@ -32,6 +31,7 @@ import { MangaMigration } from '@/features/migration/MangaMigration.ts';
|
|||||||
import { MANGA_ACTION_TO_TRANSLATION } from '@/features/manga/Manga.constants.ts';
|
import { MANGA_ACTION_TO_TRANSLATION } from '@/features/manga/Manga.constants.ts';
|
||||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||||
import { assertIsDefined } from '@/base/Asserts.ts';
|
import { assertIsDefined } from '@/base/Asserts.ts';
|
||||||
|
import { usePress } from '@/base/hooks/usePress.ts';
|
||||||
|
|
||||||
const getMangaLinkTo = (mode: MangaCardMode, mangaId: number): string => {
|
const getMangaLinkTo = (mode: MangaCardMode, mangaId: number): string => {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@@ -149,8 +149,8 @@ export const MangaCard = memo((props: MangaCardProps) => {
|
|||||||
[mode, selected, updateLibraryState, handleSelection, migrationSourceMangaId],
|
[mode, selected, updateLibraryState, handleSelection, migrationSourceMangaId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const longPressBind = useLongPress(
|
const longPressBind = usePress({
|
||||||
useCallback(
|
onLongPress: useCallback(
|
||||||
(e: any, { context }: any) => {
|
(e: any, { context }: any) => {
|
||||||
// oxlint-disable-next-line no-param-reassign
|
// oxlint-disable-next-line no-param-reassign
|
||||||
e.shiftKey = true;
|
e.shiftKey = true;
|
||||||
@@ -158,7 +158,8 @@ export const MangaCard = memo((props: MangaCardProps) => {
|
|||||||
},
|
},
|
||||||
[handleClick],
|
[handleClick],
|
||||||
),
|
),
|
||||||
);
|
onPress: handleClick,
|
||||||
|
});
|
||||||
|
|
||||||
const MangaCardComponent = useMemo(
|
const MangaCardComponent = useMemo(
|
||||||
() => (gridLayout === GridLayout.List ? MangaListCard : MangaGridCard),
|
() => (gridLayout === GridLayout.List ? MangaListCard : MangaGridCard),
|
||||||
@@ -173,7 +174,6 @@ export const MangaCard = memo((props: MangaCardProps) => {
|
|||||||
{...props}
|
{...props}
|
||||||
longPressBind={longPressBind}
|
longPressBind={longPressBind}
|
||||||
popupState={popupState}
|
popupState={popupState}
|
||||||
handleClick={handleClick}
|
|
||||||
mangaLinkTo={mangaLinkTo}
|
mangaLinkTo={mangaLinkTo}
|
||||||
isInLibrary={isInLibrary}
|
isInLibrary={isInLibrary}
|
||||||
inLibraryIndicator={inLibraryIndicator}
|
inLibraryIndicator={inLibraryIndicator}
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ export const MangaGridCard = memo(
|
|||||||
manga,
|
manga,
|
||||||
longPressBind,
|
longPressBind,
|
||||||
popupState,
|
popupState,
|
||||||
handleClick,
|
|
||||||
mangaLinkTo,
|
mangaLinkTo,
|
||||||
selected,
|
selected,
|
||||||
inLibraryIndicator,
|
inLibraryIndicator,
|
||||||
@@ -65,7 +64,6 @@ export const MangaGridCard = memo(
|
|||||||
<Link
|
<Link
|
||||||
component={RouterLink}
|
component={RouterLink}
|
||||||
{...longPressBind(() => popupState.open(optionButtonRef.current))}
|
{...longPressBind(() => popupState.open(optionButtonRef.current))}
|
||||||
onClick={handleClick}
|
|
||||||
to={mangaLinkTo}
|
to={mangaLinkTo}
|
||||||
state={Mangas.createLocationState(manga, mode)}
|
state={Mangas.createLocationState(manga, mode)}
|
||||||
onContextMenu={preventMobileContextMenu}
|
onContextMenu={preventMobileContextMenu}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ export const MangaListCard = memo(
|
|||||||
manga,
|
manga,
|
||||||
longPressBind,
|
longPressBind,
|
||||||
popupState,
|
popupState,
|
||||||
handleClick,
|
|
||||||
mangaLinkTo,
|
mangaLinkTo,
|
||||||
selected,
|
selected,
|
||||||
inLibraryIndicator,
|
inLibraryIndicator,
|
||||||
@@ -48,7 +47,6 @@ export const MangaListCard = memo(
|
|||||||
component={RouterLink}
|
component={RouterLink}
|
||||||
to={mangaLinkTo}
|
to={mangaLinkTo}
|
||||||
state={Mangas.createLocationState(manga, mode)}
|
state={Mangas.createLocationState(manga, mode)}
|
||||||
onClick={handleClick}
|
|
||||||
{...longPressBind(() => popupState.open(optionButtonRef.current))}
|
{...longPressBind(() => popupState.open(optionButtonRef.current))}
|
||||||
onContextMenu={preventMobileContextMenu}
|
onContextMenu={preventMobileContextMenu}
|
||||||
sx={{
|
sx={{
|
||||||
|
|||||||
Reference in New Issue
Block a user