mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-27 02:42:25 +08:00
fix(core): add option to disable middle click paste behavior on linux (#11496)
fix BS-3028
This commit is contained in:
@@ -25,14 +25,13 @@ import type { DefaultOpenProperty } from '../../components/doc-properties';
|
|||||||
import { BlocksuiteDocEditor, BlocksuiteEdgelessEditor } from './lit-adaper';
|
import { BlocksuiteDocEditor, BlocksuiteEdgelessEditor } from './lit-adaper';
|
||||||
import * as styles from './styles.css';
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
interface BlocksuiteEditorContainerProps {
|
interface BlocksuiteEditorContainerProps
|
||||||
|
extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
page: Store;
|
page: Store;
|
||||||
mode: DocMode;
|
mode: DocMode;
|
||||||
shared?: boolean;
|
shared?: boolean;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
className?: string;
|
|
||||||
defaultOpenProperty?: DefaultOpenProperty;
|
defaultOpenProperty?: DefaultOpenProperty;
|
||||||
style?: React.CSSProperties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AffineEditorContainer extends HTMLElement {
|
export interface AffineEditorContainer extends HTMLElement {
|
||||||
@@ -51,7 +50,7 @@ export const BlocksuiteEditorContainer = forwardRef<
|
|||||||
AffineEditorContainer,
|
AffineEditorContainer,
|
||||||
BlocksuiteEditorContainerProps
|
BlocksuiteEditorContainerProps
|
||||||
>(function AffineEditorContainer(
|
>(function AffineEditorContainer(
|
||||||
{ page, mode, className, style, shared, readonly, defaultOpenProperty },
|
{ page, mode, shared, readonly, defaultOpenProperty, ...props },
|
||||||
ref
|
ref
|
||||||
) {
|
) {
|
||||||
const rootRef = useRef<HTMLDivElement>(null);
|
const rootRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -159,15 +158,16 @@ export const BlocksuiteEditorContainer = forwardRef<
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
{...props}
|
||||||
data-testid={`editor-${page.id}`}
|
data-testid={`editor-${page.id}`}
|
||||||
dir={enableEditorRTL ? 'rtl' : 'ltr'}
|
dir={enableEditorRTL ? 'rtl' : 'ltr'}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
`editor-wrapper ${mode}-mode`,
|
`editor-wrapper ${mode}-mode`,
|
||||||
styles.docEditorRoot,
|
styles.docEditorRoot,
|
||||||
className
|
props.className
|
||||||
)}
|
)}
|
||||||
data-affine-editor-container
|
data-affine-editor-container
|
||||||
style={style}
|
style={props.style}
|
||||||
ref={rootRef}
|
ref={rootRef}
|
||||||
>
|
>
|
||||||
{mode === 'page' ? (
|
{mode === 'page' ? (
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ import type { Store } from '@blocksuite/affine/store';
|
|||||||
import { Slot } from '@radix-ui/react-slot';
|
import { Slot } from '@radix-ui/react-slot';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import { cssVar } from '@toeverything/theme';
|
import { cssVar } from '@toeverything/theme';
|
||||||
import type { CSSProperties } from 'react';
|
import type { CSSProperties, HTMLAttributes } from 'react';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import type { DefaultOpenProperty } from '../../components/doc-properties';
|
import type { DefaultOpenProperty } from '../../components/doc-properties';
|
||||||
import {
|
import {
|
||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
} from './blocksuite-editor-container';
|
} from './blocksuite-editor-container';
|
||||||
import { NoPageRootError } from './no-page-error';
|
import { NoPageRootError } from './no-page-error';
|
||||||
|
|
||||||
export type EditorProps = {
|
export interface EditorProps extends HTMLAttributes<HTMLDivElement> {
|
||||||
page: Store;
|
page: Store;
|
||||||
mode: DocMode;
|
mode: DocMode;
|
||||||
shared?: boolean;
|
shared?: boolean;
|
||||||
@@ -34,9 +34,7 @@ export type EditorProps = {
|
|||||||
defaultOpenProperty?: DefaultOpenProperty;
|
defaultOpenProperty?: DefaultOpenProperty;
|
||||||
// on Editor ready
|
// on Editor ready
|
||||||
onEditorReady?: (editor: AffineEditorContainer) => (() => void) | void;
|
onEditorReady?: (editor: AffineEditorContainer) => (() => void) | void;
|
||||||
style?: CSSProperties;
|
}
|
||||||
className?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const BlockSuiteEditorImpl = ({
|
const BlockSuiteEditorImpl = ({
|
||||||
mode,
|
mode,
|
||||||
@@ -47,6 +45,7 @@ const BlockSuiteEditorImpl = ({
|
|||||||
style,
|
style,
|
||||||
onEditorReady,
|
onEditorReady,
|
||||||
defaultOpenProperty,
|
defaultOpenProperty,
|
||||||
|
...props
|
||||||
}: EditorProps) => {
|
}: EditorProps) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const disposable = page.slots.blockUpdated.subscribe(() => {
|
const disposable = page.slots.blockUpdated.subscribe(() => {
|
||||||
@@ -111,6 +110,7 @@ const BlockSuiteEditorImpl = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<BlocksuiteEditorContainer
|
<BlocksuiteEditorContainer
|
||||||
|
{...props}
|
||||||
mode={mode}
|
mode={mode}
|
||||||
page={page}
|
page={page}
|
||||||
shared={shared}
|
shared={shared}
|
||||||
@@ -133,6 +133,7 @@ export const BlockSuiteEditor = (props: EditorProps) => {
|
|||||||
fontFamily: s.fontFamily,
|
fontFamily: s.fontFamily,
|
||||||
customFontFamily: s.customFontFamily,
|
customFontFamily: s.customFontFamily,
|
||||||
fullWidthLayout: s.fullWidthLayout,
|
fullWidthLayout: s.fullWidthLayout,
|
||||||
|
disableMiddleClickPaste: s.disableMiddleClickPaste,
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
const fontFamily = useMemo(() => {
|
const fontFamily = useMemo(() => {
|
||||||
@@ -169,12 +170,24 @@ export const BlockSuiteEditor = (props: EditorProps) => {
|
|||||||
};
|
};
|
||||||
}, [props.page]);
|
}, [props.page]);
|
||||||
|
|
||||||
|
const handleMouseDown = useCallback(
|
||||||
|
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
|
if (settings.disableMiddleClickPaste && e.button === 1) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[settings.disableMiddleClickPaste]
|
||||||
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slot style={{ '--affine-font-family': fontFamily } as CSSProperties}>
|
<Slot
|
||||||
|
style={{ '--affine-font-family': fontFamily } as CSSProperties}
|
||||||
|
onMouseDown={handleMouseDown}
|
||||||
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<EditorLoading />
|
<EditorLoading />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -487,6 +487,36 @@ const SpellCheckSettings = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MiddleClickPasteSettings = () => {
|
||||||
|
const t = useI18n();
|
||||||
|
const editorSettingService = useService(EditorSettingService);
|
||||||
|
const settings = useLiveData(editorSettingService.editorSetting.settings$);
|
||||||
|
const onToggleMiddleClickPaste = useCallback(
|
||||||
|
(checked: boolean) => {
|
||||||
|
editorSettingService.editorSetting.set(
|
||||||
|
'disableMiddleClickPaste',
|
||||||
|
checked
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[editorSettingService.editorSetting]
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<SettingRow
|
||||||
|
name={t[
|
||||||
|
'com.affine.settings.editorSettings.general.middle-click-paste.title'
|
||||||
|
]()}
|
||||||
|
desc={t[
|
||||||
|
'com.affine.settings.editorSettings.general.middle-click-paste.description'
|
||||||
|
]()}
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
checked={settings.disableMiddleClickPaste}
|
||||||
|
onChange={onToggleMiddleClickPaste}
|
||||||
|
/>
|
||||||
|
</SettingRow>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const General = () => {
|
export const General = () => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
@@ -497,6 +527,7 @@ export const General = () => {
|
|||||||
<CustomFontFamilySettings />
|
<CustomFontFamilySettings />
|
||||||
<NewDocDefaultModeSettings />
|
<NewDocDefaultModeSettings />
|
||||||
{BUILD_CONFIG.isElectron && <SpellCheckSettings />}
|
{BUILD_CONFIG.isElectron && <SpellCheckSettings />}
|
||||||
|
{environment.isLinux && <MiddleClickPasteSettings />}
|
||||||
{/* // TODO(@akumatus): implement these settings
|
{/* // TODO(@akumatus): implement these settings
|
||||||
<DeFaultCodeBlockSettings />
|
<DeFaultCodeBlockSettings />
|
||||||
*/}
|
*/}
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ const AffineEditorSettingSchema = z.object({
|
|||||||
'open-in-center-peek',
|
'open-in-center-peek',
|
||||||
])
|
])
|
||||||
.default('open-in-active-view'),
|
.default('open-in-active-view'),
|
||||||
|
// linux only:
|
||||||
|
disableMiddleClickPaste: z.boolean().default(false),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const EditorSettingSchema = BSEditorSettingSchema.merge(
|
export const EditorSettingSchema = BSEditorSettingSchema.merge(
|
||||||
|
|||||||
@@ -5167,6 +5167,14 @@ export function useAFFiNEI18N(): {
|
|||||||
* `Page`
|
* `Page`
|
||||||
*/
|
*/
|
||||||
["com.affine.settings.editorSettings.page"](): string;
|
["com.affine.settings.editorSettings.page"](): string;
|
||||||
|
/**
|
||||||
|
* `Middle click paste`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.editorSettings.general.middle-click-paste.title"](): string;
|
||||||
|
/**
|
||||||
|
* `Disable default middle click paste behavior on Linux.`
|
||||||
|
*/
|
||||||
|
["com.affine.settings.editorSettings.general.middle-click-paste.description"](): string;
|
||||||
/**
|
/**
|
||||||
* `Display bi-directional links on the doc.`
|
* `Display bi-directional links on the doc.`
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1287,6 +1287,8 @@
|
|||||||
"com.affine.settings.editorSettings.general.spell-check.title": "Spell check",
|
"com.affine.settings.editorSettings.general.spell-check.title": "Spell check",
|
||||||
"com.affine.settings.editorSettings.general.spell-check.restart-hint": "Settings changed; please restart the app. <1>Restart</1>",
|
"com.affine.settings.editorSettings.general.spell-check.restart-hint": "Settings changed; please restart the app. <1>Restart</1>",
|
||||||
"com.affine.settings.editorSettings.page": "Page",
|
"com.affine.settings.editorSettings.page": "Page",
|
||||||
|
"com.affine.settings.editorSettings.general.middle-click-paste.title": "Middle click paste",
|
||||||
|
"com.affine.settings.editorSettings.general.middle-click-paste.description": "Disable default middle click paste behavior on Linux.",
|
||||||
"com.affine.settings.editorSettings.page.display-bi-link.description": "Display bi-directional links on the doc.",
|
"com.affine.settings.editorSettings.page.display-bi-link.description": "Display bi-directional links on the doc.",
|
||||||
"com.affine.settings.editorSettings.page.display-bi-link.title": "Display bi-directional links",
|
"com.affine.settings.editorSettings.page.display-bi-link.title": "Display bi-directional links",
|
||||||
"com.affine.settings.editorSettings.page.display-doc-info.description": "Display document information on the doc.",
|
"com.affine.settings.editorSettings.page.display-doc-info.description": "Display document information on the doc.",
|
||||||
|
|||||||
Reference in New Issue
Block a user