✨(frontend) preserve @ character when esc is pressed after typing it
improves user experience by keeping @ symbol after cancelling mention trigger Signed-off-by: Cyril <c.gromoff@gmail.com>
This commit is contained in:
@@ -11,6 +11,7 @@ and this project adheres to
|
||||
- ♿(frontend) improve accessibility:
|
||||
- ♿(frontend) improve ARIA in doc grid and editor for a11y #1519
|
||||
- 🐛(docx) fix image overflow by limiting width to 600px during export #1525
|
||||
- 🐛(frontend) preserve @ character when esc is pressed after typing it #1512
|
||||
|
||||
## [3.9.0] - 2025-11-10
|
||||
|
||||
|
||||
@@ -806,6 +806,12 @@ test.describe('Doc Editor', () => {
|
||||
});
|
||||
await expect(interlinkChild1).toBeVisible({ timeout: 10000 });
|
||||
await expect(interlinkChild1.locator('svg').first()).toBeVisible();
|
||||
|
||||
await page.keyboard.press('@');
|
||||
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
await expect(editor.getByText('@')).toBeVisible();
|
||||
});
|
||||
|
||||
test('it checks multiple big doc scroll to the top', async ({
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
StyleSchema,
|
||||
} from '@blocknote/core';
|
||||
import { useBlockNoteEditor } from '@blocknote/react';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
@@ -99,6 +100,55 @@ export const SearchPage = ({
|
||||
}, 100);
|
||||
}, [inputRef]);
|
||||
|
||||
const closeSearch = (insertContent: string) => {
|
||||
updateInlineContent({
|
||||
type: 'interlinkingSearchInline',
|
||||
props: {
|
||||
disabled: true,
|
||||
trigger,
|
||||
},
|
||||
});
|
||||
|
||||
contentRef(null);
|
||||
editor.focus();
|
||||
editor.insertInlineContent([insertContent]);
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
// Keep the trigger character ('@' or '/') in the editor when closing with Escape
|
||||
closeSearch(trigger);
|
||||
} else if (e.key === 'Backspace' && search.length === 0) {
|
||||
e.preventDefault();
|
||||
closeSearch('');
|
||||
} else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
||||
// Allow arrow keys to be handled by the command menu for navigation
|
||||
const commandList = e.currentTarget
|
||||
.closest('.inline-content')
|
||||
?.nextElementSibling?.querySelector('[cmdk-list]');
|
||||
|
||||
// Create a synthetic keyboard event for the command menu
|
||||
const syntheticEvent = new KeyboardEvent('keydown', {
|
||||
key: e.key,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
commandList?.dispatchEvent(syntheticEvent);
|
||||
e.preventDefault();
|
||||
} else if (e.key === 'Enter') {
|
||||
// Handle Enter key to select the currently highlighted item
|
||||
const selectedItem = e.currentTarget
|
||||
.closest('.inline-content')
|
||||
?.nextElementSibling?.querySelector(
|
||||
'[cmdk-item][data-selected="true"]',
|
||||
) as HTMLElement;
|
||||
|
||||
selectedItem?.click();
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box as="span" $position="relative">
|
||||
<Box
|
||||
@@ -124,50 +174,7 @@ export const SearchPage = ({
|
||||
const value = (e.target as HTMLInputElement).value;
|
||||
setSearch(value);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (
|
||||
(e.key === 'Backspace' && search.length === 0) ||
|
||||
e.key === 'Escape'
|
||||
) {
|
||||
e.preventDefault();
|
||||
|
||||
updateInlineContent({
|
||||
type: 'interlinkingSearchInline',
|
||||
props: {
|
||||
disabled: true,
|
||||
trigger,
|
||||
},
|
||||
});
|
||||
|
||||
contentRef(null);
|
||||
editor.focus();
|
||||
editor.insertInlineContent(['']);
|
||||
} else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
||||
// Allow arrow keys to be handled by the command menu for navigation
|
||||
const commandList = e.currentTarget
|
||||
.closest('.inline-content')
|
||||
?.nextElementSibling?.querySelector('[cmdk-list]');
|
||||
|
||||
// Create a synthetic keyboard event for the command menu
|
||||
const syntheticEvent = new KeyboardEvent('keydown', {
|
||||
key: e.key,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
commandList?.dispatchEvent(syntheticEvent);
|
||||
e.preventDefault();
|
||||
} else if (e.key === 'Enter') {
|
||||
// Handle Enter key to select the currently highlighted item
|
||||
const selectedItem = e.currentTarget
|
||||
.closest('.inline-content')
|
||||
?.nextElementSibling?.querySelector(
|
||||
'[cmdk-item][data-selected="true"]',
|
||||
) as HTMLElement;
|
||||
|
||||
selectedItem?.click();
|
||||
e.preventDefault();
|
||||
}
|
||||
}}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
@@ -224,6 +231,8 @@ export const SearchPage = ({
|
||||
},
|
||||
});
|
||||
|
||||
contentRef(null);
|
||||
|
||||
editor.insertInlineContent([
|
||||
{
|
||||
type: 'interlinkingLinkInline',
|
||||
|
||||
Reference in New Issue
Block a user