mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
fix(editor): rework disable middle click settings for linux (#11556)
fix BS-3028 Unfortunately, I don't find out a way to disable this behavior on ff linux
This commit is contained in:
@@ -1,192 +0,0 @@
|
||||
import type {
|
||||
EdgelessEditor,
|
||||
PageEditor,
|
||||
} from '@affine/core/blocksuite/editors';
|
||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import { appendParagraphCommand } from '@blocksuite/affine/blocks/paragraph';
|
||||
import type { DocTitle } from '@blocksuite/affine/fragments/doc-title';
|
||||
import type { DocMode, RootBlockModel } from '@blocksuite/affine/model';
|
||||
import { focusBlockEnd } from '@blocksuite/affine/shared/commands';
|
||||
import { getLastNoteBlock } from '@blocksuite/affine/shared/utils';
|
||||
import type { BlockStdScope, EditorHost } from '@blocksuite/affine/std';
|
||||
import { type Store } from '@blocksuite/affine/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import type React from 'react';
|
||||
import {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
|
||||
import type { DefaultOpenProperty } from '../../components/doc-properties';
|
||||
import { BlocksuiteDocEditor, BlocksuiteEdgelessEditor } from './lit-adaper';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
interface BlocksuiteEditorContainerProps
|
||||
extends React.HTMLAttributes<HTMLDivElement> {
|
||||
page: Store;
|
||||
mode: DocMode;
|
||||
shared?: boolean;
|
||||
readonly?: boolean;
|
||||
defaultOpenProperty?: DefaultOpenProperty;
|
||||
}
|
||||
|
||||
export interface AffineEditorContainer extends HTMLElement {
|
||||
page: Store;
|
||||
doc: Store;
|
||||
docTitle: DocTitle;
|
||||
host?: EditorHost;
|
||||
model: RootBlockModel | null;
|
||||
updateComplete: Promise<boolean>;
|
||||
mode: DocMode;
|
||||
origin: HTMLDivElement;
|
||||
std: BlockStdScope;
|
||||
}
|
||||
|
||||
export const BlocksuiteEditorContainer = forwardRef<
|
||||
AffineEditorContainer,
|
||||
BlocksuiteEditorContainerProps
|
||||
>(function AffineEditorContainer(
|
||||
{ page, mode, shared, readonly, defaultOpenProperty, ...props },
|
||||
ref
|
||||
) {
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
const docRef = useRef<PageEditor>(null);
|
||||
const docTitleRef = useRef<DocTitle>(null);
|
||||
const edgelessRef = useRef<EdgelessEditor>(null);
|
||||
const featureFlags = useService(FeatureFlagService).flags;
|
||||
const enableEditorRTL = useLiveData(featureFlags.enable_editor_rtl.$);
|
||||
|
||||
/**
|
||||
* mimic an AffineEditorContainer using proxy
|
||||
*/
|
||||
const affineEditorContainerProxy = useMemo(() => {
|
||||
const api = {
|
||||
get page() {
|
||||
return page;
|
||||
},
|
||||
get doc() {
|
||||
return page;
|
||||
},
|
||||
get docTitle() {
|
||||
return docTitleRef.current;
|
||||
},
|
||||
get host() {
|
||||
return (
|
||||
(mode === 'page'
|
||||
? docRef.current?.host
|
||||
: edgelessRef.current?.host) ?? null
|
||||
);
|
||||
},
|
||||
get model() {
|
||||
return page.root as any;
|
||||
},
|
||||
get updateComplete() {
|
||||
return mode === 'page'
|
||||
? docRef.current?.updateComplete
|
||||
: edgelessRef.current?.updateComplete;
|
||||
},
|
||||
get mode() {
|
||||
return mode;
|
||||
},
|
||||
get origin() {
|
||||
return rootRef.current;
|
||||
},
|
||||
get std() {
|
||||
return mode === 'page' ? docRef.current?.std : edgelessRef.current?.std;
|
||||
},
|
||||
};
|
||||
|
||||
const proxy = new Proxy(api, {
|
||||
has(_, prop) {
|
||||
return (
|
||||
Reflect.has(api, prop) ||
|
||||
(rootRef.current ? Reflect.has(rootRef.current, prop) : false)
|
||||
);
|
||||
},
|
||||
get(_, prop) {
|
||||
if (Reflect.has(api, prop)) {
|
||||
return api[prop as keyof typeof api];
|
||||
}
|
||||
if (rootRef.current && Reflect.has(rootRef.current, prop)) {
|
||||
const maybeFn = Reflect.get(rootRef.current, prop);
|
||||
if (typeof maybeFn === 'function') {
|
||||
return maybeFn.bind(rootRef.current);
|
||||
} else {
|
||||
return maybeFn;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
}) as AffineEditorContainer;
|
||||
|
||||
return proxy;
|
||||
}, [mode, page]);
|
||||
|
||||
useImperativeHandle(ref, () => affineEditorContainerProxy, [
|
||||
affineEditorContainerProxy,
|
||||
]);
|
||||
|
||||
const handleClickPageModeBlank = useCallback(() => {
|
||||
if (shared || readonly || page.readonly) return;
|
||||
const std = affineEditorContainerProxy.host?.std;
|
||||
if (!std) {
|
||||
return;
|
||||
}
|
||||
const note = getLastNoteBlock(page);
|
||||
if (note) {
|
||||
const lastBlock = note.lastChild();
|
||||
if (
|
||||
lastBlock &&
|
||||
lastBlock.flavour === 'affine:paragraph' &&
|
||||
lastBlock.text?.length === 0
|
||||
) {
|
||||
const focusBlock = std.view.getBlock(lastBlock.id) ?? undefined;
|
||||
std.command.exec(focusBlockEnd, {
|
||||
focusBlock,
|
||||
force: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std.command.exec(appendParagraphCommand);
|
||||
}, [affineEditorContainerProxy.host?.std, page, readonly, shared]);
|
||||
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
data-testid={`editor-${page.id}`}
|
||||
dir={enableEditorRTL ? 'rtl' : 'ltr'}
|
||||
className={clsx(
|
||||
`editor-wrapper ${mode}-mode`,
|
||||
styles.docEditorRoot,
|
||||
props.className
|
||||
)}
|
||||
data-affine-editor-container
|
||||
style={props.style}
|
||||
ref={rootRef}
|
||||
>
|
||||
{mode === 'page' ? (
|
||||
<BlocksuiteDocEditor
|
||||
shared={shared}
|
||||
page={page}
|
||||
ref={docRef}
|
||||
readonly={readonly}
|
||||
titleRef={docTitleRef}
|
||||
onClickBlank={handleClickPageModeBlank}
|
||||
defaultOpenProperty={defaultOpenProperty}
|
||||
/>
|
||||
) : (
|
||||
<BlocksuiteEdgelessEditor
|
||||
shared={shared}
|
||||
page={page}
|
||||
ref={edgelessRef}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -1,30 +1,50 @@
|
||||
import { useRefEffect } from '@affine/component';
|
||||
import { EditorLoading } from '@affine/component/page-detail-skeleton';
|
||||
import type {
|
||||
EdgelessEditor,
|
||||
PageEditor,
|
||||
} from '@affine/core/blocksuite/editors';
|
||||
import { ServerService } from '@affine/core/modules/cloud';
|
||||
import {
|
||||
EditorSettingService,
|
||||
fontStyleOptions,
|
||||
} from '@affine/core/modules/editor-setting';
|
||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import {
|
||||
customImageProxyMiddleware,
|
||||
ImageProxyService,
|
||||
} from '@blocksuite/affine/blocks/image';
|
||||
import { appendParagraphCommand } from '@blocksuite/affine/blocks/paragraph';
|
||||
import type { DocTitle } from '@blocksuite/affine/fragments/doc-title';
|
||||
import { DisposableGroup } from '@blocksuite/affine/global/disposable';
|
||||
import type { DocMode } from '@blocksuite/affine/model';
|
||||
import type { DocMode, RootBlockModel } from '@blocksuite/affine/model';
|
||||
import { focusBlockEnd } from '@blocksuite/affine/shared/commands';
|
||||
import { LinkPreviewerService } from '@blocksuite/affine/shared/services';
|
||||
import { getLastNoteBlock } from '@blocksuite/affine/shared/utils';
|
||||
import type { BlockStdScope, EditorHost } from '@blocksuite/affine/std';
|
||||
import type { Store } from '@blocksuite/affine/store';
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import clsx from 'clsx';
|
||||
import type { CSSProperties, HTMLAttributes } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import type { DefaultOpenProperty } from '../../components/doc-properties';
|
||||
import {
|
||||
type AffineEditorContainer,
|
||||
BlocksuiteEditorContainer,
|
||||
} from './blocksuite-editor-container';
|
||||
import { BlocksuiteDocEditor, BlocksuiteEdgelessEditor } from './lit-adaper';
|
||||
import { NoPageRootError } from './no-page-error';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
export interface AffineEditorContainer extends HTMLElement {
|
||||
page: Store;
|
||||
doc: Store;
|
||||
docTitle: DocTitle;
|
||||
host?: EditorHost;
|
||||
model: RootBlockModel | null;
|
||||
updateComplete: Promise<boolean>;
|
||||
mode: DocMode;
|
||||
origin: HTMLDivElement;
|
||||
std: BlockStdScope;
|
||||
}
|
||||
|
||||
export interface EditorProps extends HTMLAttributes<HTMLDivElement> {
|
||||
page: Store;
|
||||
@@ -47,6 +67,113 @@ const BlockSuiteEditorImpl = ({
|
||||
defaultOpenProperty,
|
||||
...props
|
||||
}: EditorProps) => {
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
const docRef = useRef<PageEditor>(null);
|
||||
const docTitleRef = useRef<DocTitle>(null);
|
||||
const edgelessRef = useRef<EdgelessEditor>(null);
|
||||
const featureFlags = useService(FeatureFlagService).flags;
|
||||
const enableEditorRTL = useLiveData(featureFlags.enable_editor_rtl.$);
|
||||
const editorSetting = useService(EditorSettingService).editorSetting;
|
||||
const server = useService(ServerService).server;
|
||||
|
||||
const { enableMiddleClickPaste } = useLiveData(
|
||||
editorSetting.settings$.selector(s => ({
|
||||
enableMiddleClickPaste: s.enableMiddleClickPaste,
|
||||
}))
|
||||
);
|
||||
|
||||
/**
|
||||
* mimic an AffineEditorContainer using proxy
|
||||
*/
|
||||
const affineEditorContainerProxy = useMemo(() => {
|
||||
const api = {
|
||||
get page() {
|
||||
return page;
|
||||
},
|
||||
get doc() {
|
||||
return page;
|
||||
},
|
||||
get docTitle() {
|
||||
return docTitleRef.current;
|
||||
},
|
||||
get host() {
|
||||
return (
|
||||
(mode === 'page'
|
||||
? docRef.current?.host
|
||||
: edgelessRef.current?.host) ?? null
|
||||
);
|
||||
},
|
||||
get model() {
|
||||
return page.root as any;
|
||||
},
|
||||
get updateComplete() {
|
||||
return mode === 'page'
|
||||
? docRef.current?.updateComplete
|
||||
: edgelessRef.current?.updateComplete;
|
||||
},
|
||||
get mode() {
|
||||
return mode;
|
||||
},
|
||||
get origin() {
|
||||
return rootRef.current;
|
||||
},
|
||||
get std() {
|
||||
return mode === 'page' ? docRef.current?.std : edgelessRef.current?.std;
|
||||
},
|
||||
};
|
||||
|
||||
const proxy = new Proxy(api, {
|
||||
has(_, prop) {
|
||||
return (
|
||||
Reflect.has(api, prop) ||
|
||||
(rootRef.current ? Reflect.has(rootRef.current, prop) : false)
|
||||
);
|
||||
},
|
||||
get(_, prop) {
|
||||
if (Reflect.has(api, prop)) {
|
||||
return api[prop as keyof typeof api];
|
||||
}
|
||||
if (rootRef.current && Reflect.has(rootRef.current, prop)) {
|
||||
const maybeFn = Reflect.get(rootRef.current, prop);
|
||||
if (typeof maybeFn === 'function') {
|
||||
return maybeFn.bind(rootRef.current);
|
||||
} else {
|
||||
return maybeFn;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
}) as AffineEditorContainer;
|
||||
|
||||
return proxy;
|
||||
}, [mode, page]);
|
||||
|
||||
const handleClickPageModeBlank = useCallback(() => {
|
||||
if (shared || readonly || page.readonly) return;
|
||||
const std = affineEditorContainerProxy.host?.std;
|
||||
if (!std) {
|
||||
return;
|
||||
}
|
||||
const note = getLastNoteBlock(page);
|
||||
if (note) {
|
||||
const lastBlock = note.lastChild();
|
||||
if (
|
||||
lastBlock &&
|
||||
lastBlock.flavour === 'affine:paragraph' &&
|
||||
lastBlock.text?.length === 0
|
||||
) {
|
||||
const focusBlock = std.view.getBlock(lastBlock.id) ?? undefined;
|
||||
std.command.exec(focusBlockEnd, {
|
||||
focusBlock,
|
||||
force: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std.command.exec(appendParagraphCommand);
|
||||
}, [affineEditorContainerProxy.host?.std, page, readonly, shared]);
|
||||
|
||||
useEffect(() => {
|
||||
const disposable = page.slots.blockUpdated.subscribe(() => {
|
||||
disposable.unsubscribe();
|
||||
@@ -59,67 +186,104 @@ const BlockSuiteEditorImpl = ({
|
||||
};
|
||||
}, [page]);
|
||||
|
||||
const server = useService(ServerService).server;
|
||||
|
||||
const editorRef = useRefEffect(
|
||||
(editor: AffineEditorContainer) => {
|
||||
globalThis.currentEditor = editor;
|
||||
let canceled = false;
|
||||
const disposableGroup = new DisposableGroup();
|
||||
|
||||
// Invoke onLoad once the editor has been mounted to the DOM.
|
||||
if (canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// provide image proxy endpoint to blocksuite
|
||||
const imageProxyUrl = new URL(
|
||||
BUILD_CONFIG.imageProxyUrl,
|
||||
server.baseUrl
|
||||
).toString();
|
||||
|
||||
const linkPreviewUrl = new URL(
|
||||
BUILD_CONFIG.linkPreviewUrl,
|
||||
server.baseUrl
|
||||
).toString();
|
||||
|
||||
editor.std.clipboard.use(customImageProxyMiddleware(imageProxyUrl));
|
||||
page.get(LinkPreviewerService).setEndpoint(linkPreviewUrl);
|
||||
page.get(ImageProxyService).setImageProxyURL(imageProxyUrl);
|
||||
|
||||
editor.updateComplete
|
||||
.then(() => {
|
||||
if (onEditorReady) {
|
||||
const dispose = onEditorReady(editor);
|
||||
if (dispose) {
|
||||
disposableGroup.add(dispose);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error updating editor', error);
|
||||
});
|
||||
|
||||
return () => {
|
||||
canceled = true;
|
||||
disposableGroup.dispose();
|
||||
useEffect(() => {
|
||||
const editorContainer = rootRef.current;
|
||||
if (editorContainer) {
|
||||
const handleMiddleClick = (e: MouseEvent) => {
|
||||
if (!enableMiddleClickPaste && e.button === 1) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
},
|
||||
[onEditorReady, page, server]
|
||||
);
|
||||
editorContainer.addEventListener('pointerup', handleMiddleClick, {
|
||||
capture: true,
|
||||
});
|
||||
editorContainer.addEventListener('auxclick', handleMiddleClick, {
|
||||
capture: true,
|
||||
});
|
||||
return () => {
|
||||
editorContainer?.removeEventListener('pointerup', handleMiddleClick, {
|
||||
capture: true,
|
||||
});
|
||||
editorContainer?.removeEventListener('auxclick', handleMiddleClick, {
|
||||
capture: true,
|
||||
});
|
||||
};
|
||||
}
|
||||
return;
|
||||
}, [enableMiddleClickPaste]);
|
||||
|
||||
useEffect(() => {
|
||||
const editor = affineEditorContainerProxy;
|
||||
globalThis.currentEditor = editor;
|
||||
const disposableGroup = new DisposableGroup();
|
||||
let canceled = false;
|
||||
|
||||
// provide image proxy endpoint to blocksuite
|
||||
const imageProxyUrl = new URL(
|
||||
BUILD_CONFIG.imageProxyUrl,
|
||||
server.baseUrl
|
||||
).toString();
|
||||
|
||||
const linkPreviewUrl = new URL(
|
||||
BUILD_CONFIG.linkPreviewUrl,
|
||||
server.baseUrl
|
||||
).toString();
|
||||
|
||||
editor.std.clipboard.use(customImageProxyMiddleware(imageProxyUrl));
|
||||
page.get(LinkPreviewerService).setEndpoint(linkPreviewUrl);
|
||||
page.get(ImageProxyService).setImageProxyURL(imageProxyUrl);
|
||||
|
||||
editor.updateComplete
|
||||
.then(() => {
|
||||
if (onEditorReady && !canceled) {
|
||||
const dispose = onEditorReady(editor);
|
||||
if (dispose) {
|
||||
disposableGroup.add(dispose);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error updating editor', error);
|
||||
});
|
||||
|
||||
return () => {
|
||||
canceled = true;
|
||||
disposableGroup.dispose();
|
||||
};
|
||||
}, [affineEditorContainerProxy, onEditorReady, page, server]);
|
||||
|
||||
return (
|
||||
<BlocksuiteEditorContainer
|
||||
<div
|
||||
{...props}
|
||||
mode={mode}
|
||||
page={page}
|
||||
shared={shared}
|
||||
readonly={readonly}
|
||||
defaultOpenProperty={defaultOpenProperty}
|
||||
ref={editorRef}
|
||||
className={className}
|
||||
data-testid={`editor-${page.id}`}
|
||||
dir={enableEditorRTL ? 'rtl' : 'ltr'}
|
||||
className={clsx(
|
||||
`editor-wrapper ${mode}-mode`,
|
||||
styles.docEditorRoot,
|
||||
className
|
||||
)}
|
||||
style={style}
|
||||
/>
|
||||
data-affine-editor-container
|
||||
ref={rootRef}
|
||||
>
|
||||
{mode === 'page' ? (
|
||||
<BlocksuiteDocEditor
|
||||
shared={shared}
|
||||
page={page}
|
||||
ref={docRef}
|
||||
readonly={readonly}
|
||||
titleRef={docTitleRef}
|
||||
onClickBlank={handleClickPageModeBlank}
|
||||
defaultOpenProperty={defaultOpenProperty}
|
||||
/>
|
||||
) : (
|
||||
<BlocksuiteEdgelessEditor
|
||||
shared={shared}
|
||||
page={page}
|
||||
ref={edgelessRef}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -133,7 +297,6 @@ export const BlockSuiteEditor = (props: EditorProps) => {
|
||||
fontFamily: s.fontFamily,
|
||||
customFontFamily: s.customFontFamily,
|
||||
fullWidthLayout: s.fullWidthLayout,
|
||||
disableMiddleClickPaste: s.disableMiddleClickPaste,
|
||||
}))
|
||||
);
|
||||
const fontFamily = useMemo(() => {
|
||||
@@ -170,24 +333,12 @@ export const BlockSuiteEditor = (props: EditorProps) => {
|
||||
};
|
||||
}, [props.page]);
|
||||
|
||||
const handleMouseDown = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (settings.disableMiddleClickPaste && e.button === 1) {
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
[settings.disableMiddleClickPaste]
|
||||
);
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return (
|
||||
<Slot
|
||||
style={{ '--affine-font-family': fontFamily } as CSSProperties}
|
||||
onMouseDown={handleMouseDown}
|
||||
>
|
||||
<Slot style={{ '--affine-font-family': fontFamily } as CSSProperties}>
|
||||
{isLoading ? (
|
||||
<EditorLoading />
|
||||
) : (
|
||||
|
||||
@@ -10,4 +10,3 @@ registerAIEffects();
|
||||
registerTemplates();
|
||||
|
||||
export * from './blocksuite-editor';
|
||||
export * from './blocksuite-editor-container';
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
pushGlobalLoadingEventAtom,
|
||||
resolveGlobalLoadingEventAtom,
|
||||
} from '@affine/component/global-loading';
|
||||
import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor/blocksuite-editor';
|
||||
import { EditorService } from '@affine/core/modules/editor';
|
||||
import { getAFFiNEWorkspaceSchema } from '@affine/core/modules/workspace/global-schema';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -29,7 +30,6 @@ import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
import type { AffineEditorContainer } from '../../../blocksuite/block-suite-editor/blocksuite-editor-container';
|
||||
import { useAsyncCallback } from '../affine-async-hooks';
|
||||
|
||||
type ExportType = 'pdf' | 'html' | 'png' | 'markdown' | 'snapshot';
|
||||
|
||||
@@ -493,10 +493,7 @@ const MiddleClickPasteSettings = () => {
|
||||
const settings = useLiveData(editorSettingService.editorSetting.settings$);
|
||||
const onToggleMiddleClickPaste = useCallback(
|
||||
(checked: boolean) => {
|
||||
editorSettingService.editorSetting.set(
|
||||
'disableMiddleClickPaste',
|
||||
checked
|
||||
);
|
||||
editorSettingService.editorSetting.set('enableMiddleClickPaste', checked);
|
||||
},
|
||||
[editorSettingService.editorSetting]
|
||||
);
|
||||
@@ -510,7 +507,7 @@ const MiddleClickPasteSettings = () => {
|
||||
]()}
|
||||
>
|
||||
<Switch
|
||||
checked={settings.disableMiddleClickPaste}
|
||||
checked={settings.enableMiddleClickPaste}
|
||||
onChange={onToggleMiddleClickPaste}
|
||||
/>
|
||||
</SettingRow>
|
||||
|
||||
@@ -35,7 +35,7 @@ const AffineEditorSettingSchema = z.object({
|
||||
])
|
||||
.default('open-in-active-view'),
|
||||
// linux only:
|
||||
disableMiddleClickPaste: z.boolean().default(false),
|
||||
enableMiddleClickPaste: z.boolean().default(false),
|
||||
});
|
||||
|
||||
export const EditorSettingSchema = BSEditorSettingSchema.merge(
|
||||
|
||||
@@ -5176,7 +5176,7 @@ export function useAFFiNEI18N(): {
|
||||
*/
|
||||
["com.affine.settings.editorSettings.general.middle-click-paste.title"](): string;
|
||||
/**
|
||||
* `Disable default middle click paste behavior on Linux.`
|
||||
* `Enable default middle click paste behavior on Linux.`
|
||||
*/
|
||||
["com.affine.settings.editorSettings.general.middle-click-paste.description"](): string;
|
||||
/**
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
"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.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.general.middle-click-paste.description": "Enable 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.title": "Display bi-directional links",
|
||||
"com.affine.settings.editorSettings.page.display-doc-info.description": "Display document information on the doc.",
|
||||
|
||||
Reference in New Issue
Block a user